Intro

D Programming Language 1.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Sun Dec 30 20:34:42 2012

D Programming Language 1.0

“It seems to me that most of the ‘new’ programming languages fall into one of two categories: Those from academia with radical new paradigms and those from large corporations with a focus on RAD and the web. Maybe it’s time for a new language born out of practical experience implementing compilers.” -- Michael

“Great, just what I need.. another D in programming.” -- Segfault

D is a systems programming language. Its focus is on combining the power and high performance of C and C++ with the programmer productivity of modern languages like Ruby and Python. Special attention is given to the needs of quality assurance, documentation, management, portability and reliability.

The D language is statically typed and compiles directly to machine code. It’s multiparadigm, supporting many programming styles: imperative, object oriented, and metaprogramming. It’s a member of the C syntax family, and its appearance is very similar to that of C++. Here’s a quick list of features.

It is not governed by a corporate agenda or any overarching theory of programming. The needs and contributions of the D programming community form the direction it goes.

There are two versions of the language:

  1. D version 2 which is recommended for new projects.
  2. D version 1 which is in maintenance mode.

There are currently four implementations:

  1. Digital Mars dmd for Windows 1.0 2.0, x86 Linux 1.0 2.0, Mac OS X 1.0 2.0, and x86 FreeBSD 1.0, 2.0.
  2. LLVM D Compiler ldc for D version 1.
  3. Gnu D compiler gdc.
  4. D.NET compiler alpha for .NET for D version 2.

A large and growing collection of D source code and projects are at dsource. More links to innumerable D wikis, libraries, tools, media articles, etc. are at dlinks.

This document is available as a pdf, as well as in Japanese and Portugese translations. A German book Programming in D: Introduction to the new Programming Language is available, as well as a Japanese book D Language Perfect Guide, and a Turkish book D Programlama Dili Dersleri.

This is an example D program illustrating some of the capabilities:

#!/usr/bin/dmd -run
/* sh style script syntax is supported */

/* Hello World in D
   To compile:
     dmd hello.d
   or to optimize:
     dmd -O -inline -release hello.d
*/

import std.stdio;

void main(string[] args)
{
    writeln("Hello World, Reloaded");

    // auto type inference and built-in foreach
    foreach (argc, argv; args)
    {
        // Object Oriented Programming
        auto cl = new CmdLin(argc, argv);
        // Improved typesafe printf
        writeln(cl.argnum, cl.suffix, " arg: ", cl.argv);
        // Automatic or explicit memory management
        delete cl;
    }

    // Nested structs and classes
    struct specs
    {
        // all members automatically initialized
        size_t count, allocated;
    }

    // Nested functions can refer to outer
    // variables like args
    specs argspecs()
    {
        specs* s = new specs;
        // no need for '->'
        s.count = args.length;		   // get length of array with .length
        s.allocated = typeof(args).sizeof; // built-in native type properties
        foreach (argv; args)
            s.allocated += argv.length * typeof(argv[0]).sizeof;
        return *s;
    }

    // built-in string and common string operations
    writefln("argc = %d, " ~ "allocated = %d",
    argspecs().count, argspecs().allocated);
}

class CmdLin
{
    private size_t _argc;
    private string _argv;

public:
    this(size_t argc, string argv) // constructor
    {
        _argc = argc;
        _argv = argv;
    }

    size_t argnum()
    {
        return _argc + 1;
    }

    string argv()
    {
        return _argv;
    }

    string suffix()
    {
        string suffix = "th";
        switch (_argc)
        {
          case 0:
            suffix = "st";
            break;
          case 1:
            suffix = "nd";
            break;
          case 2:
            suffix = "rd";
            break;
          default:
        break;
        }
        return suffix;
    }
}

Notice: We welcome feedback about the D compiler or language, but please be explicit about any claims to intellectual property rights with a copyright or patent notice if you have such for your contributions. We want D to remain open and free to use, and do not wish to be caught by someone posting a patch to the compiler, and then later claim compensation for that work.

Forums | Comments | D | Search | Downloads | Home
Copyright © 1999-2012 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc.


Overview

  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Sun Dec 30 20:34:42 2012

Overview

What is D?

D is a general purpose systems and applications programming language. It is a higher level language than C++, but retains the ability to write high performance code and interface directly with the operating system API's and with hardware. D is well suited to writing medium to large scale million line programs with teams of developers. D is easy to learn, provides many capabilities to aid the programmer, and is well suited to aggressive compiler optimization technology. D Man

D is not a scripting language, nor an interpreted language. It doesn't come with a VM, a religion, or an overriding philosophy. It's a practical language for practical programmers who need to get the job done quickly, reliably, and leave behind maintainable, easy to understand code.

D is the culmination of decades of experience implementing compilers for many diverse languages, and attempting to construct large projects using those languages. D draws inspiration from those other languages (most especially C++) and tempers it with experience and real world practicality.

Why D?

Why, indeed. Who needs another programming language?

The software industry has come a long way since the C language was invented. Many new concepts were added to the language with C++, but backwards compatibility with C was maintained, including compatibility with nearly all the weaknesses of the original design. There have been many attempts to fix those weaknesses, but the compatibility issue frustrates it. Meanwhile, both C and C++ undergo a constant accretion of new features. These new features must be carefully fitted into the existing structure without requiring rewriting old code. The end result is very complicated - the C standard is nearly 500 pages, and the C++ standard is about 750 pages! C++ is a difficult and costly language to implement, resulting in implementation variations that make it frustrating to write fully portable C++ code.

C++ programmers tend to program in particular islands of the language, i.e. getting very proficient using certain features while avoiding other feature sets. While the code is usually portable from compiler to compiler, it can be hard to port it from programmer to programmer. A great strength of C++ is that it can support many radically different styles of programming - but in long term use, the overlapping and contradictory styles are a hindrance.

C++ implements things like resizable arrays and string concatenation as part of the standard library, not as part of the core language. Not being part of the core language has several suboptimal consequences.

Can the power and capability of C++ be extracted, redesigned, and recast into a language that is simple, orthogonal, and practical? Can it all be put into a package that is easy for compiler writers to correctly implement, and which enables compilers to efficiently generate aggressively optimized code?

Modern compiler technology has progressed to the point where language features for the purpose of compensating for primitive compiler technology can be omitted. (An example of this would be the 'register' keyword in C, a more subtle example is the macro preprocessor in C.) We can rely on modern compiler optimization technology to not need language features necessary to get acceptable code quality out of primitive compilers.

Major Goals of D

  • Reduce software development costs by at least 10% by adding in proven productivity enhancing features and by adjusting language features so that common, time-consuming bugs are eliminated from the start.
  • Make it easier to write code that is portable from compiler to compiler, machine to machine, and operating system to operating system.
  • Support multi-paradigm programming, i.e. at a minimum support imperative, structured, object oriented, and generic programming paradigms.
  • Have a short learning curve for programmers comfortable with programming in C or C++.
  • Provide low level bare metal access as required.
  • Make D substantially easier to implement a compiler for than C++.
  • Be compatible with the local C application binary interface.
  • Have a context-free grammar.
  • Easily support writing internationalized applications.
  • Incorporate Contract Programming and unit testing methodology.
  • Be able to build lightweight, standalone programs.
  • Reduce the costs of creating documentation.

Features To Keep From C/C++

The general look of D is like C and C++. This makes it easier to learn and port code to D. Transitioning from C/C++ to D should feel natural. The programmer will not have to learn an entirely new way of doing things.

Using D will not mean that the programmer will become restricted to a specialized runtime vm (virtual machine) like the Java vm or the Smalltalk vm. There is no D vm, it's a straightforward compiler that generates linkable object files. D connects to the operating system just like C does. The usual familiar tools like make will fit right in with D development.

  • The general look and feel of C/C++ is maintained. It uses the same algebraic syntax, most of the same expression and statement forms, and the general layout.
  • D programs can be written either in C style function-and-data, C++ style object-oriented, C++ style template metaprogramming, or any mix of the three.
  • The compile/link/debug development model is carried forward, although nothing precludes D from being compiled into bytecode and interpreted.
  • Exception handling. More and more experience with exception handling shows it to be a superior way to handle errors than the C traditional method of using error codes and errno globals.
  • Runtime Type Identification. This is partially implemented in C++; in D it is taken to its next logical step. Fully supporting it enables better garbage collection, better debugger support, more automated persistence, etc.
  • D maintains function link compatibility with the C calling conventions. This makes it possible for D programs to access operating system API's directly. Programmers' knowledge and experience with existing programming API's and paradigms can be carried forward to D with minimal effort.
  • Operator overloading. D programs can overload operators enabling extension of the basic types with user defined types.
  • Template Metaprogramming. Templates are a way to implement generic programming. Other ways include using macros or having a variant data type. Using macros is out. Variants are straightforward, but inefficient and lack type checking. The difficulties with C++ templates are their complexity, they don't fit well into the syntax of the language, all the various rules for conversions and overloading fitted on top of it, etc. D offers a much simpler way of doing templates.
  • RAII (Resource Acquisition Is Initialization). RAII techniques are an essential component of writing reliable software.
  • Down and dirty programming. D retains the ability to do down-and-dirty programming without resorting to referring to external modules compiled in a different language. Sometimes, it's just necessary to coerce a pointer or dip into assembly when doing systems work. D's goal is not to prevent down and dirty programming, but to minimize the need for it in solving routine coding tasks.

Features To Drop

  • C source code compatibility. Extensions to C that maintain source compatibility have already been done (C++ and ObjectiveC). Further work in this area is hampered by so much legacy code it is unlikely that significant improvements can be made.
  • Link compatibility with C++. The C++ runtime object model is just too complicated - properly supporting it would essentially imply making D a full C++ compiler too.
  • The C preprocessor. Macro processing is an easy way to extend a language, adding in faux features that aren't really there (invisible to the symbolic debugger). Conditional compilation, layered with #include text, macros, token concatenation, etc., essentially forms not one language but two merged together with no obvious distinction between them. Even worse (or perhaps for the best) the C preprocessor is a very primitive macro language. It's time to step back, look at what the preprocessor is used for, and design support for those capabilities directly into the language.
  • Multiple inheritance. It's a complex feature of debatable value. It's very difficult to implement in an efficient manner, and compilers are prone to many bugs in implementing it. Nearly all the value of MI can be handled with single inheritance coupled with interfaces and aggregation. What's left does not justify the weight of MI implementation.
  • Namespaces. An attempt to deal with the problems resulting from linking together independently developed pieces of code that have conflicting names. The idea of modules is simpler and works much better.
  • Tag name space. This misfeature of C is where the tag names of structs are in a separate but parallel symbol table. C++ attempted to merge the tag name space with the regular name space, while retaining backward compatibility with legacy C code. The result is needlessly confusing.
  • Forward declarations. C compilers semantically only know about what has lexically preceded the current state. C++ extends this a little, in that class members can rely on forward referenced class members. D takes this to its logical conclusion, forward declarations are no longer necessary at the module level. Functions can be defined in a natural order rather than the typical inside-out order commonly used in C programs to avoid writing forward declarations.
  • Include files. A major cause of slow compiles as each compilation unit must reparse enormous quantities of header files. Include files should be done as importing a symbol table.
  • Trigraphs and digraphs. Unicode is the future.
  • Non-virtual member functions. In C++, a class designer decides in advance if a function is to be virtual or not. Forgetting to retrofit the base class member function to be virtual when the function gets overridden is a common (and very hard to find) coding error. Making all member functions virtual, and letting the compiler decide if there are no overrides and hence can be converted to non-virtual, is much more reliable.
  • Bit fields of arbitrary size. Bit fields are a complex, inefficient feature rarely used.
  • Support for 16 bit computers. No consideration is given in D for mixed near/far pointers and all the machinations necessary to generate good 16 bit code. The D language design assumes at least a 32 bit flat memory space. D will fit smoothly into 64 bit architectures.
  • Mutual dependence of compiler passes. In C++, successfully parsing the source text relies on having a symbol table, and on the various preprocessor commands. This makes it impossible to preparse C++ source, and makes writing code analyzers and syntax directed editors painfully difficult to do correctly.
  • Compiler complexity. Reducing the complexity of an implementation makes it more likely that multiple, correct implementations are available.
  • Dumbed down floating point. If one is using hardware that implements modern floating point, it should be available to the programmer rather than having floating point support dumbed down to the lowest common denominator among machines. In particular, a D implementation must support IEEE 754 arithmetic and if extended precision is available it must be supported.
  • Template overloading of < and > symbols. This choice has caused years of bugs, grief, and confusion for programmers, C++ implementors, and C++ source parsing tool vendors. It makes it impossible to parse C++ code correctly without doing a nearly complete C++ compiler. D uses !( and ) which fit neatly and unambiguously into the grammar.

Who D is For

  • Programmers who routinely use lint or similar code analysis tools to eliminate bugs before the code is even compiled.
  • People who compile with maximum warning levels turned on and who instruct the compiler to treat warnings as errors.
  • Programming managers who are forced to rely on programming style guidelines to avoid common C bugs.
  • Those who decide the promise of C++ object oriented programming is not fulfilled due to the complexity of it.
  • Programmers who enjoy the expressive power of C++ but are frustrated by the need to expend much effort explicitly managing memory and finding pointer bugs.
  • Projects that need built-in testing and verification.
  • Teams who write apps with a million lines of code in it.
  • Programmers who think the language should provide enough features to obviate the continual necessity to manipulate pointers directly.
  • Numerical programmers. D has many features to directly support features needed by numerics programmers, like extended floating point precision, core support for complex and imaginary floating types and defined behavior for NaN's and infinities. (These are added in the new C99 standard, but not in C++.)
  • Programmers who write half their application in scripting langauges like Ruby and Python, and the other half in C++ to speed up the bottlenecks. D has many of the productivity features of Ruby and Python, making it possible to write the entire app in one language.
  • D's lexical analyzer and parser are totally independent of each other and of the semantic analyzer. This means it is easy to write simple tools to manipulate D source perfectly without having to build a full compiler. It also means that source code can be transmitted in tokenized form for specialized applications.

Who D is Not For

  • Realistically, nobody is going to convert million line C or C++ programs into D. Since D does not compile unmodified C/C++ source code, D is not for legacy apps. (However, D supports legacy C API's very well. D can connect directly to any code that exposes a C interface.)
  • As a first programming language - Basic or Java is more suitable for beginners. D makes an excellent second language for intermediate to advanced programmers.
  • Language purists. D is a practical language, and each feature of it is evaluated in that light, rather than by an ideal. For example, D has constructs and semantics that virtually eliminate the need for pointers for ordinary tasks. But pointers are still there, because sometimes the rules need to be broken. Similarly, casts are still there for those times when the typing system needs to be overridden.

Major Features of D

This section lists some of the more interesting features of D in various categories.

Object Oriented Programming

Classes

D's object oriented nature comes from classes. The inheritance model is single inheritance enhanced with interfaces. The class Object sits at the root of the inheritance hierarchy, so all classes implement a common set of functionality. Classes are instantiated by reference, and so complex code to clean up after exceptions is not required.

Operator Overloading

Classes can be crafted that work with existing operators to extend the type system to support new types. An example would be creating a bignumber class and then overloading the +, -, * and / operators to enable using ordinary algebraic syntax with them.

Productivity

Modules

Source files have a one-to-one correspondence with modules. Instead of #include'ing the text of a file of declarations, just import the module. There is no need to worry about multiple imports of the same module, no need to wrapper header files with #ifndef/#endif or #pragma once kludges, etc.

Declaration vs Definition

C++ usually requires that functions and classes be declared twice - the declaration that goes in the .h header file, and the definition that goes in the .c source file. This is an error prone and tedious process. Obviously, the programmer should only need to write it once, and the compiler should then extract the declaration information and make it available for symbolic importing. This is exactly how D works.

Example:

class ABC
{
    int func() { return 7; }
    static int z = 7;
}
int q;

There is no longer a need for a separate definition of member functions, static members, externs, nor for clumsy syntaxes like:

int ABC::func() { return 7; }
int ABC::z = 7;
extern int q;

Note: Of course, in C++, trivial functions like { return 7; } are written inline too, but complex ones are not. In addition, if there are any forward references, the functions need to be prototyped. The following will not work in C++:

class Foo
{
    int foo(Bar *c) { return c->bar(); }
};

class Bar
{
  public:
    int bar() { return 3; }
};

But the equivalent D code will work:

class Foo
{
    int foo(Bar c) { return c.bar; }
}

class Bar
{
    int bar() { return 3; }
}

Whether a D function is inlined or not is determined by the optimizer settings.

Templates

D templates offer a clean way to support generic programming while offering the power of partial specialization. Template classes and template functions are available, along with variadic template arguments and tuples.

Associative Arrays

Associative arrays are arrays with an arbitrary data type as the index rather than being limited to an integer index. In essence, associated arrays are hash tables. Associative arrays make it easy to build fast, efficient, bug-free symbol tables.

Real Typedefs

C and C++ typedefs are really type aliases, as no new type is really introduced. D implements real typedefs, where:

typedef int handle;

really does create a new type handle. Type checking is enforced, and typedefs participate in function overloading. For example:

int foo(int i);
int foo(handle h);

Documentation

Documentation has traditionally been done twice - first there are comments documenting what a function does, and then this gets rewritten into a separate html or man page. And naturally, over time, they'll tend to diverge as the code gets updated and the separate documentation doesn't. Being able to generate the requisite polished documentation directly from the comments embedded in the source will not only cut the time in half needed to prepare documentation, it will make it much easier to keep the documentation in sync with the code. Ddoc is the specification for the D documentation generator. This page was generated by Ddoc, too.

Although third party tools exist to do this for C++, they have some serious shortcomings:

  • It is spectacularly difficult to parse C++ 100% correctly. To do so really requires a full C++ compiler. Third party tools tend to parse only a subset of C++ correctly, so their use will constrain the source code to that subset.
  • Different compilers support different versions of C++ and have different extensions to C++. Third party tools have a problem matching all these variations.
  • Third party tools may not be available for all the desired platforms, and they're necessarily on a different upgrade cycle from the compilers.
  • Having it builtin to the compiler means it is standardized across all D implementations. Having a default one ready to go at all times means it is far more likely to be used.

Functions

D has the expected support for ordinary functions including global functions, overloaded functions, inlining of functions, member functions, virtual functions, function pointers, etc. In addition:

Nested Functions

Functions can be nested within other functions. This is highly useful for code factoring, locality, and function closure techniques.

Function Literals

Anonymous functions can be embedded directly into an expression.

Dynamic Closures

Nested functions and class member functions can be referenced with closures (also called delegates), making generic programming much easier and type safe.

In Out and Inout Parameters

Not only does specifying this help make functions more self-documenting, it eliminates much of the necessity for pointers without sacrificing anything, and it opens up possibilities for more compiler help in finding coding problems.

Such makes it possible for D to directly interface to a wider variety of foreign API's. There would be no need for workarounds like "Interface Definition Languages".

Arrays

C arrays have several faults that can be corrected:

  • Dimension information is not carried around with the array, and so has to be stored and passed separately. The classic example of this are the argc and argv parameters to main(int argc , char *argv []). (In D, main is declared as main(char[][] args ).)
  • Arrays are not first class objects. When an array is passed to a function, it is converted to a pointer, even though the prototype confusingly says it's an array. When this conversion happens, all array type information gets lost.
  • C arrays cannot be resized. This means that even simple aggregates like a stack need to be constructed as a complex class.
  • C arrays cannot be bounds checked, because they don't know what the array bounds are.
  • Arrays are declared with the [] after the identifier. This leads to very clumsy syntax to declare things like a pointer to an array:
    int (*array)[3];

    In D, the [] for the array go on the left:

    int[3]* array;		// declares a pointer to an array of 3 ints
long[] func(int x);	// declares a function returning an array of longs

    which is much simpler to understand.

D arrays come in several varieties: pointers, static arrays, dynamic arrays, and associative arrays.

See Arrays.

Strings

String manipulation is so common, and so clumsy in C and C++, that it needs direct support in the language. Modern languages handle string concatenation, copying, etc., and so does D. Strings are a direct consequence of improved array handling.

Resource Management

Automatic Memory Management

D memory allocation is fully garbage collected. Empirical experience suggests that a lot of the complicated features of C++ are necessary in order to manage memory deallocation. With garbage collection, the language gets much simpler.

There's a perception that garbage collection is for lazy, junior programmers. I remember when that was said about C++, after all, there's nothing in C++ that cannot be done in C, or in assembler for that matter.

Garbage collection eliminates the tedious, error prone memory allocation tracking code necessary in C and C++. This not only means much faster development time and lower maintenance costs, but the resulting program frequently runs faster!

Sure, garbage collectors can be used with C++, and I've used them in my own C++ projects. The language isn't friendly to collectors, however, impeding the effectiveness of it. Much of the runtime library code can't be used with collectors.

For a fuller discussion of this, see garbage collection.

Explicit Memory Management

Despite D being a garbage collected language, the new and delete operations can be overridden for particular classes so that a custom allocator can be used.

RAII

RAII is a modern software development technique to manage resource allocation and deallocation. D supports RAII in a controlled, predictable manner that is independent of the garbage collection cycle.

Performance

Lightweight Aggregates

D supports simple C style structs, both for compatibility with C data structures and because they're useful when the full power of classes is overkill.

Inline Assembler

Device drivers, high performance system applications, embedded systems, and specialized code sometimes need to dip into assembly language to get the job done. While D implementations are not required to implement the inline assembler, it is defined and part of the language. Most assembly code needs can be handled with it, obviating the need for separate assemblers or DLL's.

Many D implementations will also support intrinsic functions analogously to C's support of intrinsics for I/O port manipulation, direct access to special floating point operations, etc.

Reliability

A modern language should do all it can to help the programmer flush out bugs in the code. Help can come in many forms; from making it easy to use more robust techniques, to compiler flagging of obviously incorrect code, to runtime checking.

Contracts

Contract Programming (invented by B. Meyer) is a revolutionary technique to aid in ensuring the correctness of programs. D's version of DBC includes function preconditions, function postconditions, class invariants, and assert contracts. See Contracts for D's implementation.

Unit Tests

Unit tests can be added to a class, such that they are automatically run upon program startup. This aids in verifying, in every build, that class implementations weren't inadvertently broken. The unit tests form part of the source code for a class. Creating them becomes a natural part of the class development process, as opposed to throwing the finished code over the wall to the testing group.

Unit tests can be done in other languages, but the result is kludgy and the languages just aren't accommodating of the concept. Unit testing is a main feature of D. For library functions it works out great, serving both to guarantee that the functions actually work and to illustrate how to use the functions.

Consider the many C++ library and application code bases out there for download on the web. How much of it comes with *any* verification tests at all, let alone unit testing? Less than 1%? The usual practice is if it compiles, we assume it works. And we wonder if the warnings the compiler spits out in the process are real bugs or just nattering about nits.

Along with Contract Programming, unit testing makes D far and away the best language for writing reliable, robust systems applications. Unit testing also gives us a quick-and-dirty estimate of the quality of some unknown piece of D code dropped in our laps - if it has no unit tests and no contracts, it's unacceptable.

Debug Attributes and Statements

Now debug is part of the syntax of the language. The code can be enabled or disabled at compile time, without the use of macros or preprocessing commands. The debug syntax enables a consistent, portable, and understandable recognition that real source code needs to be able to generate both debug compilations and release compilations.

Exception Handling

The superior try-catch-finally model is used rather than just try-catch. There's no need to create dummy objects just to have the destructor implement the finally semantics.

Synchronization

Multithreaded programming is becoming more and more mainstream, and D provides primitives to build multithreaded programs with. Synchronization can be done at either the method or the object level.

synchronized int func() { ... }

Synchronized functions allow only one thread at a time to be executing that function.

The synchronize statement puts a mutex around a block of statements, controlling access either by object or globally.

Support for Robust Techniques

  • Dynamic arrays instead of pointers
  • Reference variables instead of pointers
  • Reference objects instead of pointers
  • Garbage collection instead of explicit memory management
  • Built-in primitives for thread synchronization
  • No macros to inadvertently slam code
  • Inline functions instead of macros
  • Vastly reduced need for pointers
  • Integral type sizes are explicit
  • No more uncertainty about the signed-ness of chars
  • No need to duplicate declarations in source and header files.
  • Explicit parsing support for adding in debug code.

Compile Time Checks

  • Stronger type checking
  • No empty ; for loop bodies
  • Assignments do not yield boolean results
  • Deprecating of obsolete API's

Runtime Checking

  • assert() expressions
  • array bounds checking
  • undefined case in switch exception
  • out of memory exception
  • In, out, and class invariant Contract Programming support

Compatibility

Operator precedence and evaluation rules

D retains C operators and their precedence rules, order of evaluation rules, and promotion rules. This avoids subtle bugs that might arise from being so used to the way C does things that one has a great deal of trouble finding bugs due to different semantics.

Direct Access to C API's

Not only does D have data types that correspond to C types, it provides direct access to C functions. There is no need to write wrapper functions, parameter swizzlers, nor code to copy aggregate members one by one.

Support for all C data types

Making it possible to interface to any C API or existing C library code. This support includes structs, unions, enums, pointers, and all C99 types. D includes the capability to set the alignment of struct members to ensure compatibility with externally imposed data formats.

OS Exception Handling

D's exception handling mechanism will connect to the way the underlying operating system handles exceptions in an application.

Uses Existing Tools

D produces code in standard object file format, enabling the use of standard assemblers, linkers, debuggers, profilers, exe compressors, and other analyzers, as well as linking to code written in other languages.

Project Management

Versioning

D provides built-in support for generation of multiple versions of a program from the same text. It replaces the C preprocessor #if/#endif technique.

Deprecation

As code evolves over time, some old library code gets replaced with newer, better versions. The old versions must be available to support legacy code, but they can be marked as deprecated. Code that uses deprecated versions will be normally flagged as illegal, but would be allowed by a compiler switch. This will make it easy for maintenance programmers to identify any dependence on deprecated features.

Sample D Program (sieve.d)

/* Sieve of Eratosthenes prime numbers */

import std.stdio;

bool[8191] flags;

int main()
{   int i, count, prime, k, iter;

    writefln("10 iterations");
    for (iter = 1; iter <= 10; iter++)
    {	count = 0;
    flags[] = 1;
    for (i = 0; i < flags.length; i++)
    {   if (flags[i])
        {	prime = i + i + 3;
        k = i + prime;
        while (k < flags.length)
        {
            flags[k] = 0;
            k += prime;
        }
        count += 1;
        }
    }
    }
    writefln("%d primes", count);
    return 0;
}


Windows

  • Home
Last update Sun Dec 30 20:34:43 2012

D for Win32

This describes the D implementation for 32 bit Windows systems. Naturally, Windows specific D features are not portable to other platforms.

Instead of the:

#include <windows.h>

of C, in D there is:

import std.c.windows.windows;

Calling Conventions

In C, the Windows API calling conventions are __stdcall. In D, it is simply:

extern (Windows)
{
    /* ... function declarations ... */
}

The Windows linkage attribute sets both the calling convention and the name mangling scheme to be compatible with Windows.

For functions that in C would be __declspec(dllimport) or __declspec(dllexport), use the export attribute:

export void func(int foo);

If no function body is given, it's imported. If a function body is given, it's exported.

Windows Executables

Windows GUI applications can be written with D. A sample such can be found in \dmd\samples\d\winsamp.d

These are required:

  1. Instead of a main function serving as the entry point, a WinMain function is needed.
  2. WinMain must follow this form:
    import std.c.windows.windows;

extern (C) void gc_init();
extern (C) void gc_term();
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleDtor();
extern (C) void _moduleUnitTests();

extern (Windows)
int WinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    int result;

    gc_init();			// initialize garbage collector
    _minit();			// initialize module constructor table

    try
    {
    _moduleCtor();		// call module constructors
    _moduleUnitTests();	// run unit tests (optional)

    result = myWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

    _moduleDtor();		// call module destructors
    }

    catch (Object o)		// catch any uncaught exceptions
    {
    MessageBoxA(null, cast(char *)o.toString(), "Error",
            MB_OK | MB_ICONEXCLAMATION);
    result = 0;		// failed
    }

    gc_term();			// run finalizers; terminate garbage collector
    return result;
}

int myWinMain(HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    /* ... insert user code here ... */
}
    The myWinMain() function is where the user code goes, the rest of WinMain is boilerplate to initialize and shut down the D runtime system.
  3. A .def (Module Definition File) with at least the following two lines in it:
    EXETYPE NT
SUBSYSTEM WINDOWS
    Without those, Win32 will open a text console window whenever the application is run.
  4. The presence of WinMain() is recognized by the compiler causing it to emit a reference to __acrtused_dll and the phobos.lib runtime library.


Writing Win32 DLLs

Last update Sun Dec 30 20:34:43 2012

Writing Win32 DLLs in D

DLLs (Dynamic Link Libraries) are one of the foundations of system programming for Windows. The D programming language enables the creation of several different types of DLLs.

For background information on what DLLs are and how they work Chapter 11 of Jeffrey Richter's book Advanced Windows is indispensible.

This guide will show how to create DLLs of various types with D.

  • DLLs with a C interface
  • DLLs that are COM servers
  • D code calling D code in DLLs

DLLs with a C Interface

A DLL presenting a C interface can connect to any other code in a language that supports calling C functions in a DLL.

DLLs can be created in D in roughly the same way as in C. A DllMain() is required, looking like:

import std.c.windows.windows;
HINSTANCE g_hInst;

extern (C)
{
    void gc_init();
    void gc_term();
    void _minit();
    void _moduleCtor();
    void _moduleUnitTests();
}

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
    case DLL_PROCESS_ATTACH:
        gc_init();			// initialize GC
        _minit();			// initialize module list
        _moduleCtor();		// run module constructors
        _moduleUnitTests();		// run module unit tests
        break;

    case DLL_PROCESS_DETACH:
        gc_term();			// shut down GC
        break;

    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        // Multiple threads not supported yet
        return false;
    }
    g_hInst=hInstance;
    return true;
}

Notes:

  • The _moduleUnitTests() call is optional.
  • The presence of DllMain() is recognized by the compiler causing it to emit a reference to __acrtused_dll and the phobos.lib runtime library.
Link with a .def (Module Definition File) along the lines of:
LIBRARY         MYDLL
DESCRIPTION     'My DLL written in D'

EXETYPE		NT
CODE            PRELOAD DISCARDABLE
DATA            PRELOAD SINGLE

EXPORTS
        DllGetClassObject       @2
        DllCanUnloadNow         @3
        DllRegisterServer       @4
        DllUnregisterServer     @5

The functions in the EXPORTS list are for illustration. Replace them with the actual exported functions from MYDLL. Alternatively, use implib. Here's an example of a simple DLL with a function print() which prints a string:

mydll2.d:

module mydll;
export void dllprint() { printf("hello dll world\n"); }

Note: We use printfs in these examples instead of writefln to make the examples as simple as possible.

mydll.def:

LIBRARY "mydll.dll"
EXETYPE NT
SUBSYSTEM WINDOWS
CODE SHARED EXECUTE
DATA WRITE

Put the code above that contains DllMain() into a file dll.d. Compile and link the dll with the following command:

C:>dmd -ofmydll.dll mydll2.d dll.d mydll.def
C:>implib/system mydll.lib mydll.dll
C:>

which will create mydll.dll and mydll.lib. Now for a program, test.d, which will use the dll:

test.d:

import mydll;

int main()
{
   mydll.dllprint();
   return 0;
}

Create a clone of mydll2.d that doesn't have the function bodies:

mydll.d:

export void dllprint();
Compile and link with the command:
C:>dmd test.d mydll.lib
C:>
and run:
C:>test
hello dll world
C:>

Memory Allocation

D DLLs use garbage collected memory management. The question is what happens when pointers to allocated data cross DLL boundaries? If the DLL presents a C interface, one would assume the reason for that is to connect with code written in other languages. Those other languages will not know anything about D's memory management. Thus, the C interface will have to shield the DLL's callers from needing to know anything about it.

There are many approaches to solving this problem:

  • Do not return pointers to D gc allocated memory to the caller of the DLL. Instead, have the caller allocate a buffer, and have the DLL fill in that buffer.
  • Retain a pointer to the data within the D DLL so the GC will not free it. Establish a protocol where the caller informs the D DLL when it is safe to free the data.
  • Use operating system primitives like VirtualAlloc() to allocate memory to be transferred between DLLs.
  • Use std.c.stdlib.malloc() (or another non-gc allocator) when allocating data to be returned to the caller. Export a function that will be used by the caller to free the data.

COM Programming

Many Windows API interfaces are in terms of COM (Common Object Model) objects (also called OLE or ActiveX objects). A COM object is an object who's first field is a pointer to a vtbl[], and the first 3 entries in that vtbl[] are for QueryInterface(), AddRef(), and Release().

For understanding COM, Kraig Brockshmidt's Inside OLE is an indispensible resource.

COM objects are analogous to D interfaces. Any COM object can be expressed as a D interface, and every D object with an interface X can be exposed as a COM object X. This means that D is compatible with COM objects implemented in other languages.

While not strictly necessary, the Phobos library provides an Object useful as a super class for all D COM objects, called ComObject. ComObject provides a default implementation for QueryInterface(), AddRef(), and Release().

Windows COM objects use the Windows calling convention, which is not the default for D, so COM functions need to have the attribute extern (Windows). So, to write a COM object:

import std.c.windows.com;

class MyCOMobject : ComObject
{
    extern (Windows):
    ...
}
The sample code includes an example COM client program and server DLL.

D code calling D code in DLLs

Having DLLs in D be able to talk to each other as if they were statically linked together is, of course, very desirable as code between applications can be shared, and different DLLs can be independently developed.

The underlying difficulty is what to do about garbage collection (gc). Each EXE and DLL will have their own gc instance. While these gc's can coexist without stepping on each other, it's redundant and inefficient to have multiple gc's running. The idea explored here is to pick one gc and have the DLLs redirect their gc's to use that one. The one gc used here will be the one in the EXE file, although it's also possible to make a separate DLL just for the gc.

The example will show both how to statically load a DLL, and to dynamically load/unload it.

Starting with the code for the DLL, mydll.d:

/*
 * MyDll demonstration of how to write D DLLs.
 */

import std.c.stdio;
import std.c.stdlib;
import std.string;
import std.c.windows.windows;
import std.gc;

HINSTANCE   g_hInst;

extern (C)
{
    void _minit();
    void _moduleCtor();
    void _moduleDtor();
    void _moduleUnitTests();
}

extern (Windows)
    BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
        case DLL_PROCESS_ATTACH:
        printf("DLL_PROCESS_ATTACH\n");
        break;

        case DLL_PROCESS_DETACH:
        printf("DLL_PROCESS_DETACH\n");
        std.c.stdio._fcloseallp = null; // so stdio doesn't get closed
        break;

        case DLL_THREAD_ATTACH:
        printf("DLL_THREAD_ATTACH\n");
        return false;

        case DLL_THREAD_DETACH:
        printf("DLL_THREAD_DETACH\n");
        return false;
    }
    g_hInst = hInstance;
    return true;
}

export void MyDLL_Initialize(void* gc)
{
    printf("MyDLL_Initialize()\n");
    std.gc.setGCHandle(gc);
    _minit();
    _moduleCtor();
//  _moduleUnitTests();
}

export void MyDLL_Terminate()
{
    printf("MyDLL_Terminate()\n");
    _moduleDtor();			// run module destructors
    std.gc.endGCHandle();
}

static this()
{
    printf("static this for mydll\n");
}

static ~this()
{
    printf("static ~this for mydll\n");
}

/* --------------------------------------------------------- */

class MyClass
{
    char[] concat(char[] a, char[] b)
    {
    return a ~ " " ~ b;
    }

    void free(char[] s)
    {
    delete s;
    }
}

export MyClass getMyClass()
{
    return new MyClass();
}
DllMain
This is the main entry point for any D DLL. It gets called by the C startup code (for DMC++, the source is \dm\src\win32\dllstart.c). The printf's are placed there so one can trace how it gets called. Notice that the initialization and termination code seen in the earlier DllMain sample code isn't there. This is because the initialization will depend on who is loading the DLL, and how it is loaded (statically or dynamically). There isn't much to do here. The only oddity is the setting of std.c.stdio._fcloseallp to null. If this is not set to null, the C runtime will flush and close all the standard I/O buffers (like stdout, stderr, etc.) shutting off further output. Setting it to null defers the responsibility for that to the caller of the DLL.

MyDLL_Initialize
So instead we'll have our own DLL initialization routine so exactly when it is called can be controlled. It must be called after the caller has initialized itself, the Phobos runtime library, and the module constructors (this would normally be by the time main() was entered). This function takes one argument, a handle to the caller's gc. We'll see how that handle is obtained later. Instead of gc_init() being called to initialize the DLL's gc, std.gc.setGCHandle() is called and passed the handle to which gc to use. This step informs the caller's gc which data areas of the DLL to scan. Afterwards follows the call to the _minit() to initialize the module tables, and _moduleCtor() to run the module constructors. _moduleUnitTests() is optional and runs the DLL's unit tests. The function is exported as that is how a function is made visible outside of a DLL.

MyDLL_Terminate
Correspondingly, this function terminates the DLL, and is called prior to unloading it. It has two jobs; calling the DLL's module destructors via _moduleDtor() and informing the runtime that the DLL will no longer be using the caller's gc via std.gc.endGCHandle(). That last step is critical, as the DLL will be unmapped from memory, and if the gc continues to scan its data areas it will cause segment faults.

static this, static ~this
These are examples of the module's static constructor and destructor, here with a print in each to verify that they are running and when.

MyClass
This is an example of a class that can be exported from and used by the caller of a DLL. The concat member function allocates some gc memory, and free frees gc memory.

getMyClass
An exported factory that allocates an instance of MyClass and returns a reference to it.

To build the mydll.dll DLL:
  1. dmd -c mydll -g
    Compiles mydll.d into mydll.obj. -g turns on debug info generation.
  2. dmd mydll.obj \dmd\lib\gcstub.obj mydll.def -g -L/map
    Links mydll.obj into a DLL named mydll.dll. gcstub.obj is not required, but it prevents the bulk of the gc code from being linked in, since it will not be used anyway. It saves about 12Kb. mydll.def is the Module Definition File, and has the contents:
    LIBRARY         MYDLL
DESCRIPTION     'MyDll demonstration DLL'
EXETYPE		NT
CODE            PRELOAD DISCARDABLE
DATA            PRELOAD SINGLE
    -g turns on debug info generation, and -L/map generates a map file mydll.map.
  3. implib /noi /system mydll.lib mydll.dll
    Creates an import library mydll.lib suitable for linking in with an application that will be statically loading mydll.dll.

Here's test.d, a sample application that makes use of mydll.dll. There are two versions, one statically binds to the DLL, and the other dynamically loads it.

import std.stdio;
import std.gc;

import mydll;

//version=DYNAMIC_LOAD;

version (DYNAMIC_LOAD)
{
    import std.c.windows.windows;

    alias void function(void*) MyDLL_Initialize_fp;
    alias void function() MyDLL_Terminate_fp;
    alias MyClass function() getMyClass_fp;

    int main()
    {	HMODULE h;
    FARPROC fp;
    MyDLL_Initialize_fp mydll_initialize;
    MyDLL_Terminate_fp  mydll_terminate;

    getMyClass_fp  getMyClass;
    MyClass c;

    printf("Start Dynamic Link...\n");

    h = LoadLibraryA("mydll.dll");
    if (h == null)
    {   printf("error loading mydll.dll\n");
        return 1;
    }

    fp = GetProcAddress(h, "D5mydll16MyDLL_InitializeFPvZv");
    if (fp == null)
    {   printf("error loading symbol MyDLL_Initialize()\n");
        return 1;
    }

    mydll_initialize = cast(MyDLL_Initialize_fp) fp;
    (*mydll_initialize)(std.gc.getGCHandle());

    fp = GetProcAddress(h, "D5mydll10getMyClassFZC5mydll7MyClass");
    if (fp == null)
    {   printf("error loading symbol getMyClass()\n");
        return 1;
    }

    getMyClass = cast(getMyClass_fp) fp;
    c = (*getMyClass)();
    foo(c);

    fp = GetProcAddress(h, "D5mydll15MyDLL_TerminateFZv");
    if (fp == null)
    {   printf("error loading symbol MyDLL_Terminate()\n");
        return 1;
    }

    mydll_terminate = cast(MyDLL_Terminate_fp) fp;
    (*mydll_terminate)();

    if (FreeLibrary(h) == FALSE)
    {   printf("error freeing mydll.dll\n");
        return 1;
    }

    printf("End...\n");
    return 0;
    }
}
else
{   // static link the DLL

    int main()
    {
    printf("Start Static Link...\n");
    MyDLL_Initialize(std.gc.getGCHandle());
    foo(getMyClass());
    MyDLL_Terminate();
    printf("End...\n");
    return 0;
    }
}

void foo(MyClass c)
{
    char[] s;

    s = c.concat("Hello", "world!");
    writefln(s);
    c.free(s);
    delete c;
}

Let's start with the statically linked version, which is simpler. It's compiled and linked with the command:

C:>dmd test mydll.lib -g

Note how it is linked with mydll.lib, the import library for mydll.dll. The code is straightforward, it initializes mydll.lib with a call to MyDLL_Initialize(), passing the handle to test.exe's gc. Then, we can use the DLL and call its functions just as if it were part of test.exe. In foo(), gc memory is allocated and freed both by test.exe and mydll.dll. When we're done using the DLL, it is terminated with MyDLL_Terminate().

Running it looks like this:

C:>test
DLL_PROCESS_ATTACH
Start Static Link...
MyDLL_Initialize()
static this for mydll
Hello world!
MyDLL_Terminate()
static ~this for mydll
End...
C:>

The dynamically linked version is a little harder to set up. Compile and link it with the command:

C:>dmd test -version=DYNAMIC_LOAD -g

The import library mydll.lib is not needed. The DLL is loaded with a call to LoadLibraryA(), and each exported function has to be retrieved via a call to GetProcAddress(). An easy way to get the decorated name to pass to GetProcAddress() is to copy and paste it from the generated mydll.map file under the Export heading. Once this is done, we can use the member functions of the DLL classes as if they were part of test.exe. When done, release the DLL with FreeLibrary().

Running it looks like this:

C:>test
Start Dynamic Link...
DLL_PROCESS_ATTACH
MyDLL_Initialize()
static this for mydll
Hello world!
MyDLL_Terminate()
static ~this for mydll
DLL_PROCESS_DETACH
End...
C:>


Converting C .h Files to D Modules

Last update Sun Dec 30 20:34:43 2012

Converting C .h Files to D Modules

While D cannot directly compile C source code, it can easily interface to C code, be linked with C object files, and call C functions in DLLs. The interface to C code is normally found in C .h files. So, the trick to connecting with C code is in converting C .h files to D modules. This turns out to be difficult to do mechanically since inevitably some human judgement must be applied. This is a guide to doing such conversions.

Preprocessor

.h files can sometimes be a bewildering morass of layers of macros, #include files, #ifdef's, etc. D doesn't include a text preprocessor like the C preprocessor, so the first step is to remove the need for it by taking the preprocessed output. For DMC (the Digital Mars C/C++ compiler), the command:
dmc -c program.h -e -l
will create a file program.lst which is the source file after all text preprocessing.

Remove all the #if, #ifdef, #include, etc. statements.

Linkage

Generally, surround the entire module with:
extern (C)
{
     /* ...file contents... */
}
to give it C linkage.

Types

A little global search and replace will take care of renaming the C types to D types. The following table shows a typical mapping for 32 bit C code:

Mapping C type to D type
C type | D type
long double | real
unsigned long long | ulong
long long | long
unsigned long | uint
long | int
unsigned | uint
unsigned short | ushort
signed char | byte
unsigned char | ubyte
wchar_t | wchar or dchar
bool | bool, byte, int
size_t | size_t
ptrdiff_t | ptrdiff_t

NULL

NULL and ((void*)0) should be replaced with null.

Numeric Literals

Any ‘L’ or ‘l’ numeric literal suffixes should be removed, as a C long is (usually) the same size as a D int. Similarly, ‘LL’ suffixes should be replaced with a single ‘L’. Any ‘u’ suffix will work the same in D.

String Literals

In most cases, any ‘L’ prefix to a string can just be dropped, as D will implicitly convert strings to wide characters if necessary. However, one can also replace:
L"string"
with:
"string"w	// for 16 bit wide characters
"string"d	// for 32 bit wide characters

Macros

Lists of macros like:
#define FOO	1
#define BAR	2
#define ABC	3
#define DEF	40
can be replaced with:
enum
{   FOO = 1,
    BAR = 2,
    ABC = 3,
    DEF = 40
}
or with:
const int FOO = 1;
const int BAR = 2;
const int ABC = 3;
const int DEF = 40;
Function style macros, such as:
#define MAX(a,b) ((a) < (b) ? (b) : (a))
can be replaced with functions:
int MAX(int a, int b) { return (a < b) ? b : a; }
The functions, however, won't work if they appear inside static initializers that must be evaluated at compile time rather than runtime. To do it at compile time, a template can be used:
#define GT_DEPTH_SHIFT  (0)
#define GT_SIZE_SHIFT   (8)
#define GT_SCHEME_SHIFT (24)
#define GT_DEPTH_MASK   (0xffU << GT_DEPTH_SHIFT)
#define GT_TEXT         ((0x01) << GT_SCHEME_SHIFT)

/* Macro that constructs a graphtype */
#define GT_CONSTRUCT(depth,scheme,size) \
    ((depth) | (scheme) | ((size) << GT_SIZE_SHIFT))

/* Common graphtypes */
#define GT_TEXT16  GT_CONSTRUCT(4, GT_TEXT, 16)
The corresponding D version would be:
const uint GT_DEPTH_SHIFT  = 0;
const uint GT_SIZE_SHIFT   = 8;
const uint GT_SCHEME_SHIFT = 24;
const uint GT_DEPTH_MASK   = 0xffU << GT_DEPTH_SHIFT;
const uint GT_TEXT         = 0x01 << GT_SCHEME_SHIFT;

// Template that constructs a graphtype
template GT_CONSTRUCT(uint depth, uint scheme, uint size)
{
 // notice the name of the const is the same as that of the template
 const uint GT_CONSTRUCT = (depth | scheme | (size << GT_SIZE_SHIFT));
}

// Common graphtypes
const uint GT_TEXT16 = GT_CONSTRUCT!(4, GT_TEXT, 16);

Declaration Lists

D doesn't allow declaration lists to change the type. Hence:
int *p, q, t[3], *s;
should be written as:
int* p, s;
int q;
int[3] t;

Void Parameter Lists

Functions that take no parameters:
int foo(void);
are in D:
int foo();

Const Type Modifiers

D has const as a storage class, not a type modifier. Hence, just drop any const used as a type modifier:
void foo(const int *p, char *const q);
becomes:
void foo(int* p, char* q);

Extern Global C Variables

Whenever a global variable is declared in D, it is also defined. But if it's also defined by the C object file being linked in, there will be a multiple definition error. To fix this problem, use the extern storage class. For example, given a C header file named foo.h:
struct Foo { };
struct Foo bar;
It can be replaced with the D modules, foo.d:
struct Foo { }
extern (C)
{
    extern Foo bar;
}

Typedef

alias is the D equivalent to the C typedef:
typedef int foo;
becomes:
alias int foo;

Structs

Replace declarations like:
typedef struct Foo
{   int a;
    int b;
} Foo, *pFoo, *lpFoo;
with:
struct Foo
{   int a;
    int b;
}
alias Foo* pFoo, lpFoo;

Struct Member Alignment

A good D implementation by default will align struct members the same way as the C compiler it was designed to work with. But if the .h file has some #pragma's to control alignment, they can be duplicated with the D align attribute:
#pragma pack(1)
struct Foo
{
    int a;
    int b;
};
#pragma pack()
becomes:
struct Foo
{
  align (1):
    int a;
    int b;
}

Nested Structs

struct Foo
{
    int a;
    struct Bar
    {
    int c;
    } bar;
};

struct Abc
{
    int a;
    struct
    {
    int c;
    } bar;
};
becomes:
struct Foo
{
    int a;
    struct Bar
    {
    int c;
    }
    Bar bar;
}

struct Abc
{
    int a;
    struct
    {
    int c;
    }
}

__cdecl, __pascal, __stdcall

int __cdecl x;
int __cdecl foo(int a);
int __pascal bar(int b);
int __stdcall abc(int c);
becomes:
extern (C) int x;
extern (C) int foo(int a);
extern (Pascal) int bar(int b);
extern (Windows) int abc(int c);

__declspec(dllimport)

__declspec(dllimport) int __stdcall foo(int a);
becomes:
export extern (Windows) int foo(int a);

__fastcall

Unfortunately, D doesn't support the __fastcall convention. Therefore, a shim will be needed, either written in C:
int __fastcall foo(int a);

int myfoo(int a)
{
    return foo(int a);
}
and compiled with a C compiler that supports __fastcall and linked in, or compile the above, disassemble it with obj2asm and insert it in a D myfoo shim with inline assembler.


D 1.0 FAQ

Last update Sun Dec 30 20:34:43 2012

D 1.0 FAQ

The same questions keep cropping up, so the obvious thing to do is prepare a FAQ.

D 2.0 FAQ

C++ FAQ

  • The D wiki FAQ page with many more questions answered
  • What does D have that C++ doesn't?
  • Why the name D?
  • When can I get a D compiler?
  • Is there linux port of D?
  • Is there a GNU version of D?
  • How do I write my own D compiler for CPU X?
  • Where can I get a GUI library for D?
  • Where can I get an IDE for D?
  • What about templates?
  • Why emphasize implementation ease?
  • Why is [expletive deleted] printf left in?
  • Will D be open source?
  • Why fall through on switch statements?
  • Why should I use D instead of Java?
  • Doesn't C++ support strings, etc. with STL?
  • Can't garbage collection be done in C++ with an add-on library?
  • Can't unit testing be done in C++ with an add-on library?
  • Why have an asm statement in a portable language?
  • What is the point of 80 bit reals?
  • How do I do anonymous struct/unions in D?
  • How do I get printf() to work with strings?
  • Why are floating point values default initialized to NaN rather than 0?
  • Why is overloading of the assignment operator not supported?
  • The '~' is not on my keyboard?
  • Can I link in C object files created with another compiler?
  • Why not support regular expression literals with the /foo/g syntax?
  • Why is the D front end written in C++ rather than D?
  • Why aren't all Digital Mars programs translated to D?
  • When should I use a foreach loop rather than a for?
  • Why doesn't D have an interface to C++ as well as C?
  • Why doesn't D use reference counting for garbage collection?
  • Isn't garbage collection slow and non-deterministic?

Why the name D?

The original name was the Mars Programming Language. But my friends kept calling it D, and I found myself starting to call it D. The idea of D being a successor to C goes back at least as far as 1988, as in this thread.

Where can I get a D compiler?

Right here.

Is there a linux port of D?

Yes, the D compiler includes a linux version.

Is there a GNU version of D?

Yes, David Friedman has integrated the D frontend with GCC.

How do I write my own D compiler for CPU X?

Burton Radons has written a back end. you can use as a guide.

Where can I get a GUI library for D?

Since D can call C functions, any GUI library with a C interface is accessible from D. Various D GUI libraries and ports can be found at AvailableGuiLibraries.

Where can I get an IDE for D?

Try Elephant, Poseidon, or LEDS.

What about templates?

D now supports advanced templates.

Why emphasize implementation ease?

Isn't ease of use for the user of the language more important? Yes, it is. But a vaporware language is useless to everyone. The easier a language is to implement, the more robust implementations there will be. In C's heyday, there were 30 different commercial C compilers for the IBM PC. Not many made the transition to C++. In looking at the C++ compilers on the market today, how many years of development went into each? At least 10 years? Programmers waited years for the various pieces of C++ to get implemented after they were specified. If C++ was not so enormously popular, it's doubtful that very complex features like multiple inheritance, templates, etc., would ever have been implemented.

I suggest that if a language is easier to implement, then it is likely also easier to understand. Isn't it better to spend time learning to write better programs than language arcana? If a language can capture 90% of the power of C++ with 10% of its complexity, I argue that is a worthwhile tradeoff.

Why is printf in D?

printf is not part of D, it is part of C's standard runtime library which is accessible from D. D's standard runtime library has std.stdio.writefln, which is as powerful as printf but much easier to use.

Will D be open source?

The front end for D is open source, and the source comes with the compiler. The runtime library is completely open source. David Friedman has integrated the D frontend with GCC to create gdc, a completely open source implementation of D.

Why fall through on switch statements?

Many people have asked for a requirement that there be a break between cases in a switch statement, that C's behavior of silently falling through is the cause of many bugs.

The reason D doesn't change this is for the same reason that integral promotion rules and operator precedence rules were kept the same - to make code that looks the same as in C operate the same. If it had subtly different semantics, it will cause frustratingly subtle bugs.

Why should I use D instead of Java?

D is distinct from Java in purpose, philosophy and reality. See this comparison.

Java is designed to be write once, run everywhere. D is designed for writing efficient native system apps. Although D and Java share the notion that garbage collection is good and multiple inheritance is bad <g>, their different design goals mean the languages have very different feels.

Doesn't C++ support strings, etc. with STL?

In the C++ standard library are mechanisms for doing strings, dynamic arrays, associative arrays, bounds checked arrays, and complex numbers.

Sure, all this stuff can be done with libraries, following certain coding disciplines, etc. But you can also do object oriented programming in C (I've seen it done). Isn't it incongruous that something like strings, supported by the simplest BASIC interpreter, requires a very large and complicated infrastructure to support? Just the implementation of a string type in STL is over two thousand lines of code, using every advanced feature of templates. How much confidence can you have that this is all working correctly, how do you fix it if it is not, what do you do with the notoriously inscrutable error messages when there's an error using it, how can you be sure you are using it correctly (so there are no memory leaks, etc.)?

D's implementation of strings is simple and straightforward. There's little doubt about how to use it, no worries about memory leaks, error messages are to the point, and it isn't hard to see if it is working as expected or not.

Can't garbage collection be done in C++ with an add-on library?

Yes, I use one myself. It isn't part of the language, though, and requires some subverting of the language to make it work. Using gc with C++ isn't for the standard or casual C++ programmer. Building it into the language, like in D, makes it practical for everyday programming chores.

GC isn't that hard to implement, either, unless you're building one of the more advanced ones. But a more advanced one is like building a better optimizer - the language still works 100% correctly even with a simple, basic one. The programming community is better served by multiple implementations competing on quality of code generated rather than by which corners of the spec are implemented at all.

Can't unit testing be done in C++ with an add-on library?

Sure. Try one out and then compare it with how D does it. It'll be quickly obvious what an improvement building it into the language is.

Why have an asm statement in a portable language?

An asm statement allows assembly code to be inserted directly into a D function. Assembler code will obviously be inherently non-portable. D is intended, however, to be a useful language for developing systems apps. Systems apps almost invariably wind up with system dependent code in them anyway, inline asm isn't much different. Inline asm will be useful for things like accessing special CPU instructions, accessing flag bits, special computational situations, and super optimizing a piece of code.

Before the C compiler had an inline assembler, I used external assemblers. There was constant grief because many, many different versions of the assembler were out there, the vendors kept changing the syntax of the assemblers, there were many different bugs in different versions, and even the command line syntax kept changing. What it all meant was that users could not reliably rebuild any code that needed assembler. An inline assembler provided reliability and consistency.

What is the point of 80 bit reals?

More precision enables more accurate floating point computations to be done, especially when adding together large numbers of small real numbers. Prof. Kahan, who designed the Intel floating point unit, has an eloquent paper on the subject.

How do I do anonymous struct/unions in D?

import std.stdio;

struct Foo
{
    union { int a; int b; }
    struct { int c; int d; }
}

void main()
{
    writefln(
      "Foo.sizeof = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d",
      Foo.sizeof,
      Foo.a.offsetof,
      Foo.b.offsetof,
      Foo.c.offsetof,
      Foo.d.offsetof);
}

How do I get printf() to work with strings?

In C, the normal way to printf a string is to use the %s format:
char s[8];
strcpy(s, "foo");
printf("string = '%s'\n", s);
Attempting this in D, as in:
char[] s;
s = "foo";
printf("string = '%s'\n", s);
usually results in garbage being printed, or an access violation. The cause is that in C, strings are terminated by a 0 character. The %s format prints until a 0 is encountered. In D, strings are not 0 terminated, the size is determined by a separate length value. So, strings are printf'd using the %.*s format:
char[] s;
s = "foo";
printf("string = '%.*s'\n", s);

which will behave as expected. Remember, though, that printf's %.*s will print until the length is reached or a 0 is encountered, so D strings with embedded 0's will only print up to the first 0.

Of course, the easier solution is just use std.stdio.writefln which works correctly with D strings.

Why are floating point values default initialized to NaN rather than 0?

A floating point value, if no explicit initializer is given, is initialized to NaN (Not A Number):
double d;	// d is set to double.nan
NaNs have the interesting property in that whenever a NaN is used as an operand in a computation, the result is a NaN. Therefore, NaNs will propagate and appear in the output whenever a computation made use of one. This implies that a NaN appearing in the output is an unambiguous indication of the use of an uninitialized variable.

If 0.0 was used as the default initializer for floating point values, its effect could easily be unnoticed in the output, and so if the default initializer was unintended, the bug may go unrecognized.

The default initializer value is not meant to be a useful value, it is meant to expose bugs. Nan fills that role well.

But surely the compiler can detect and issue an error message for variables used that are not initialized? Most of the time, it can, but not always, and what it can do is dependent on the sophistication of the compiler's internal data flow analysis. Hence, relying on such is unportable and unreliable.

Because of the way CPUs are designed, there is no NaN value for integers, so D uses 0 instead. It doesn't have the advantages of error detection that NaN has, but at least errors resulting from unintended default initializations will be consistent and therefore more debuggable.

Why is overloading of the assignment operator not supported?

Overloading of the assignment operator for structs is supported in D 2.0.

The '~' is not on my keyboard?

On PC keyboards, hold down the [Alt] key and press the 1, 2, and 6 keys in sequence on the numeric pad. That will generate a '~' character.

Can I link in C object files created with another compiler?

DMD produces OMF (Microsoft Object Module Format) object files while other compilers such as VC++ produce COFF object files. DMD's output is designed to work with DMC, the Digital Mars C compiler, which also produces object files in OMF format.

The OMF format that DMD uses is a Microsoft defined format based on an earlier Intel designed one. Microsoft at one point decided to abandon it in favor of a Microsoft defined variant on COFF.

Using the same object format doesn't mean that any C library in that format will successfully link and run. There is a lot more compatibility required - such as calling conventions, name mangling, compiler helper functions, and hidden assumptions about the way things work. If DMD produced Microsoft COFF output files, there is still little chance that they would work successfully with object files designed and tested for use with VC. There were a lot of problems with this back when Microsoft's compilers did generate OMF.

Having a different object file format makes it helpful in identifying library files that were not tested to work with DMD. If they are not, weird problems would result even if they successfully managed to link them together. It really takes an expert to get a binary built with a compiler from one vendor to work with the output of another vendor's compiler.

That said, the linux version of DMD produces object files in the ELF format which is standard on linux, and it is specifically designed to work with the standard linux C compiler, gcc.

There is one case where using existing C libraries does work - when those libraries come in the form of a DLL conforming to the usual C ABI interface. The linkable part of this is called an "import library", and Microsoft COFF format import libraries can be successfully converted to DMD OMF using the coff2omf tool.

Why not support regular expression literals with the /foo/g syntax?

There are two reasons:

  1. The /foo/g syntax would make it impossible to separate the lexer from the parser, as / is the divide token.
  2. There are already 3 string types; adding the regex literals would add 3 more. This would proliferate through much of the compiler, debugger info, and library, and is not worth it.

Why is the D front end written in C++ rather than D?

The front end is in C++ in order to interface to the existing gcc and dmd back ends. It's also meant to be easily interfaced to other existing back ends, which are likely written in C++. The D implementation of DMDScript, which performs better than the C++ version, shows that there is no problem writing a professional quality compiler in 100% D.

Why aren't all Digital Mars programs translated to D?

There is little benefit to translating a complex, debugged, working application from one language to another. But new Digital Mars apps are implemented in D.

When should I use a foreach loop rather than a for?

Is it just performance or readability?

By using foreach, you are letting the compiler decide on the optimization rather than worrying about it yourself. For example - are pointers or indices better? Should I cache the termination condition or not? Should I rotate the loop or not? The answers to these questions are not easy, and can vary from machine to machine. Like register assignment, let the compiler do the optimization.

for (int i = 0; i < foo.length; i++)
or:
for (int i = 0; i < foo.length; ++i)
or:
for (T* p = &foo[0]; p < &foo[length]; p++)
or:
T* pend = &foo[length];
for (T* p = &foo[0]; p < pend; ++p)
or:
T* pend = &foo[length];
T* p = &foo[0];
if (p < pend)
{
    do
    {
    ...
    } while (++p < pend);
}
and, of course, should I use size_t or int?
for (size_t i = 0; i < foo.length; i++)
Let the compiler pick!
foreach (v; foo)
    ...

Note that we don't even need to know what the type T needs to be, thus avoiding bugs when T changes. I don't even have to know if foo is an array, or an associative array, or a struct, or a collection class. This will also avoid the common fencepost bug:

for (int i = 0; i <= foo.length; i++)

And it also avoids the need to manually create a temporary if foo is a function call.

The only reason to use a for loop is if your loop does not fit in the conventional form, like if you want to change the termination condition on the fly.

Why doesn't D have an interface to C++ as well as C?

Attempting to have D interface with C++ is nearly as complicated as writing a C++ compiler, which would destroy the goal of having D be a reasonably easy language to implement. For people with an existing C++ code base that they must work with, they are stuck with C++ (they can't move it to any other language, either).

There are many issues that would have to be resolved in order for D code to call some arbitrary C++ code that is presumed to be unmodifiable. This list certainly isn't complete, it's just to show the scope of the difficulties involved.

  1. D source code is unicode, C++'s is ASCII with code pages. Or not. It's unspecified. This impacts the contents of string literals.
  2. std::string cannot deal with multibyte UTF.
  3. C++ has a tag name space. D does not. Some sort of renaming would have to happen.
  4. C++ code often relies on compiler specific extensions.
  5. C++ has namespaces. D has modules. There is no obvious mapping between the two.
  6. C++ views source code as one gigantic file (after preprocessing). D sees source code as a hierarchy of modules and packages.
  7. Enum name scoping rules behave differently.
  8. C++ code, despite decades of attempts to replace macro features with inbuilt ones, relies more heavily than ever on layer after layer of arbitrary macros. There is no D analog for token pasting or stringizing.
  9. Macro names have global scope across #include files, but are local to the gigantic source files.
  10. C++ has arbitrary multiple inheritance and virtual base classes. D does not.
  11. C++ does not distinguish between in, out and ref (i.e. inout) parameters.
  12. The C++ name mangling varies from compiler to compiler.
  13. C++ throws exceptions of arbitrary type, not just descendants of Object.
  14. C++ overloads based on const and volatile. D does not.
  15. C++ overloads operators in significantly different ways - for example, operator[]() overloading for lvalue and rvalue is based on const overloading and a proxy class.
  16. C++ overloads operators like < completely independently of >.
  17. C++ overloads indirection (operator*).
  18. C++ does not distinguish between a class and a struct object.
  19. The vtbl[] location and layout is different between C++ and D.
  20. The way RTTI is done is completely different. C++ has no classinfo.
  21. D does not allow overloading of assignment.
  22. D does not have constructors or destructors for struct objects.
  23. D does not have two phase lookup, nor does it have Koenig (ADL) lookup.
  24. C++ relates classes with the 'friend' system, D uses packages and modules.
  25. C++ class design tends to revolve around explicit memory allocation issues, D's do not.
  26. D's template system is very different.
  27. C++ has 'exception specifications'.
  28. C++ has global operator overloading.
  29. C++ name mangling depends on const and volatile being type modifiers. Since D does not have const and volatile type modifiers, there is no straightforward way to infer the C++ mangled identifier from a D type.

The bottom line is the language features affect the design of the code. C++ designs just don't fit with D. Even if you could find a way to automatically adapt between the two, the result will be about as enticing as the left side of a honda welded to the right side of a camaro.

Why doesn't D use reference counting for garbage collection?

Reference counting has its advantages, but some severe disadvantages:

  • Cyclical data structures won't get freed.
  • Every pointer copy requires an increment and a corresponding decrement - including when simply passing a reference to a function.
  • In a multithreaded app, the incs and decs must be synchronized.
  • Exception handlers (finally blocks) must be inserted to handle all the decs so there are no leaks. Contrary to assertions otherwise, there is no such thing as "zero overhead exceptions."
  • In order to support slicing and interior pointers, as well as supporting reference counting on arbitrary allocations of non-object data, a separate "wrapper" object must be allocated for each allocation to be ref counted. This essentially doubles the number of allocations needed.
  • The wrapper object will mean that all pointers will need to be double-dereferenced to access the data.
  • Fixing the compiler to hide all this stuff from the programmer will make it difficult to interface cleanly with C.
  • Ref counting can fragment the heap thereby consuming more memory just like the gc can, though the gc typically will consume more memory overall.
  • Ref counting does not eliminate latency problems, it just reduces them.

The proposed C++ shared_ptr<>, which implements ref counting, suffers from all these faults. I haven't seen a heads up benchmark of shared_ptr<> vs mark/sweep, but I wouldn't be surprised if shared_ptr<> turned out to be a significant loser in terms of both performance and memory consumption.

That said, D may in the future optionally support some form of ref counting, as rc is better for managing scarce resources like file handles.

Isn't garbage collection slow and non-deterministic?

Yes, but all dynamic memory management is slow and non-deterministic, including malloc/free. If you talk to the people who actually do real time software, they don't use malloc/free precisely because they are not deterministic. They preallocate all data. However, the use of GC instead of malloc enables advanced language constructs (especially, more powerful array syntax), which greatly reduce the number of memory allocations which need to be made. This can mean that GC is actually faster than explict management.


The D Style

Last update Sun Dec 30 20:34:43 2012

The D Style

The D Style is a set of style conventions for writing D programs. The D Style is not enforced by the compiler, it is purely cosmetic and a matter of choice. Adhering to the D Style, however, will make it easier for others to work with your code and easier for you to work with others' code. The D Style can form the starting point for a project style guide customized for your project team.

Submissions to Phobos and other official D source code will follow these guidelines.

White Space

  • One statement per line.
  • Use spaces instead of hardware tabs.
  • Each indentation level will be four columns.
  • Operators are separated by single spaces from their operands.
  • Two blank lines separating function bodies.
  • One blank line separating variable declarations from statements in function bodies.

Comments

  • Use // comments to document a single line:
    statement;	// comment
statement;	// comment
  • Use block comments to document a multiple line block of statements:
    /* comment
 * comment
 */
 statement;
 statement;
  • Use version (none) to ‘comment out’ a piece of trial code that is syntactically valid:
      version (none)
  {
    /* comment
     * comment
     */
     statement;
     statement;
  }
    It can be turned on with version(all):
      version (all)
  {
    /* comment
     * comment
     */
     statement;
     statement;
  }
  • Use nesting comments to ‘comment out’ a piece of syntactically invalid code:
    /+++++
    /* comment
     * comment
     */
     { statement;
       statement;
 +++++/

Naming Conventions

General
Names formed by joining multiple words should have each word other than the first capitalized. Names shall not begin with an underscore ‘_’ unless they are private member variables.
int myFunc();
Module
Module and package names are all lower case, and only contain the characters [a..z][0..9][_]. This avoids problems dealing with case insensitive file systems.
C Modules
Modules that are interfaces to C functions go into the "c" package, for example:
import std.c.stdio;
Module names should be all lower case.
Class, Struct, Union, Enum, Template names
are capitalized.
class Foo;
class FooAndBar;
An exception is that eponymous templates that return a value instead of a type should not be capitalized, as they are conceptually more similar to functions. ------------------------- template GetSomeType(T) {} template isSomeType(T) {} -------------------------
Function names
Function names are not capitalized.
int done();
int doneProcessing();
Const names
Are in all caps.
Enum member names
Are in lowerCamelCase.

Meaningless Type Aliases

Things like:

alias void VOID;
alias int INT;
alias int* pint;

should be avoided.

Declaration Style

Since the declarations are left-associative, left justify them:

int[] x, y;	// makes it clear that x and y are the same type
int** p, q;	// makes it clear that p and q are the same type

to emphasize their relationship. Do not use the C style:

int []x, y;	// confusing since y is also an int[]
int **p, q;	// confusing since q is also an int**

Operator Overloading

Operator overloading is a powerful tool to extend the basic types supported by the language. But being powerful, it has great potential for creating obfuscated code. In particular, the existing D operators have conventional meanings, such as ‘+’ means ‘add’ and ‘<<’ means ‘shift left’. Overloading operator ‘+’ with a meaning different from ‘add’ is arbitrarily confusing and should be avoided.

Hungarian Notation

Using hungarian notation to denote the type of a variable is a bad idea. However, using notation to denote the purpose of a variable (that cannot be expressed by its type) is often a good practice.

Documentation

All public declarations will be documented in Ddoc format.

Unit Tests

As much as practical, all functions will be exercised by unit tests using unittest blocks immediately following the function to be tested. Every path of code should be executed at least once, verified by the code coverage analyzer.


Word Count

Last update Sun Dec 30 20:34:43 2012

Example: wc

This program is the D version of the classic wc (wordcount) C program. It serves to demonstrate how to read files, slice arrays, and simple symbol table management with associative arrays. It has two main code paths, one for smaller files that will fit in memory, and one using buffered file I/O for files that are larger.

import std.stdio;
import std.stream;

int main (string[] args)
{
    int w_total;
    int l_total;
    ulong c_total;
    int[string] dictionary;

    writefln("   lines   words   bytes file");
    foreach (arg; args[1 .. args.length])
    {
    int w_cnt, l_cnt;
    bool inword;

    auto c_cnt = std.file.getSize(arg);
    if (c_cnt < 10_000_000)
    {
        size_t wstart;
        auto input = cast(string)std.file.read(arg);

        foreach (j, c; input)
        {
        if (c == '\n')
            ++l_cnt;
        if (c >= '0' && c <= '9')
        {
        }
        else if (c >= 'a' && c <= 'z' ||
             c >= 'A' && c <= 'Z')
        {
            if (!inword)
            {
            wstart = j;
            inword = true;
            ++w_cnt;
            }
        }
        else if (inword)
        {   auto word = input[wstart .. j];

            dictionary[word]++;
            inword = false;
        }
        }
        if (inword)
        {   auto w = input[wstart .. input.length];
        dictionary[w]++;
        }
    }
    else
    {
        auto f = new BufferedFile(arg);
        string buf;

        while (!f.eof())
        {   char c;

        f.read(c);
        if (c == '\n')
            ++l_cnt;
        if (c >= '0' && c <= '9')
        {
            if (inword)
            buf ~= c;
        }
        else if (c >= 'a' && c <= 'z' ||
                 c >= 'A' && c <= 'Z')
        {
            if (!inword)
            {
            buf.length = 1;
            buf[0] = c;
            inword = 1;
            ++w_cnt;
            }
            else
            buf ~= c;
        }
        else if (inword)
        {
            if (++dictionary[buf] == 1)
            buf = null;
            inword = 0;
        }
        }
        if (inword)
        {
        dictionary[buf]++;
        }
    }
    writefln("%8s%8s%8s %s\n", l_cnt, w_cnt, c_cnt, arg);
    l_total += l_cnt;
    w_total += w_cnt;
    c_total += c_cnt;
    }

    if (args.length > 2)
    {
    writefln("--------------------------------------\n%8s%8s%8s total",
        l_total, w_total, c_total);
    }

    writefln("--------------------------------------");

    foreach (word1; dictionary.keys.sort)
    {
    writefln("%3s %s", dictionary[word1], word1);
    }
    return 0;
}


Future Directions

Last update Sun Dec 30 20:34:43 2012

Future Directions

The following new features for D are planned for post 1.0, but the details have not been worked out:

  1. Template inheritance.
  2. Array operations.


Change Log

Last update Tue Jan 1 19:35:29 2013

D Change Log

Under Construction

  1. Shared libraries for Linux
Version D 1.076 Dec 31, 2012
  • New/Changed Features
  • DMD Bugs Fixed
  • Phobos Bugs Fixed
  • What's new for D 1.076
  • What's new for D 1.075
  • What's new for D 1.074
  • What's new for D 1.073
  • What's new for D 1.072
  • What's new for D 1.071
  • What's new for D 1.070
  • What's new for D 1.069
  • What's new for D 1.068
  • What's new for D 1.067
  • What's new for D 1.066
  • What's new for D 1.065
  • What's new for D 1.064
  • What's new for D 1.063
  • What's new for D 1.062
  • What's new for D 1.061
  • What's new for D 1.060
  • What's new for D 1.059
  • What's new for D 1.058
  • What's new for D 1.057
  • What's new for D 1.056
  • What's new for D 1.055
  • What's new for D 1.054
  • What's new for D 1.053
  • What's new for D 1.052
  • What's new for D 1.051
  • What's new for D 1.050
  • What's new for D 1.049
  • What's new for D 1.048
  • What's new for D 1.047
  • What's new for D 1.046
  • What's new for D 1.045
  • What's new for D 1.044
  • What's new for D 1.043
  • What's new for D 1.042
  • What's new for D 1.041
  • What's new for D 1.040
  • What's new for D 1.039
  • What's new for D 1.038
  • What's new for D 1.037
  • What's new for D 1.036
  • What's new for D 1.035
  • What's new for D 1.034
  • What's new for D 1.033
  • What's new for D 1.032
  • What's new for D 1.031
  • What's new for D 1.030
  • What's new for D 1.029
  • What's new for D 1.028
  • What's new for D 1.027
  • What's new for D 1.026
  • What's new for D 1.025
  • What's new for D 1.024
  • What's new for D 1.023
  • What's new for D 1.022
  • What's new for D 1.021
  • What's new for D 1.020
  • What's new for D 1.019
  • What's new for D 1.018
  • What's new for D 1.017
  • What's new for D 1.016
  • What's new for D 1.015
  • What's new for D 1.014
  • What's new for D 1.013
  • What's new for D 1.012
  • What's new for D 1.011
  • What's new for D 1.010
  • What's new for D 1.009
  • What's new for D 1.007
  • What's new for D 1.006
  • What's new for D 1.005
  • What's new for D 1.004
  • What's new for D 1.003
  • What's new for D 1.002
  • What's new for D 1.001
  • change log for D 2.0
  • older versions
  • even older versions
  • Download latest stable (1.030) D compiler for Win32 and x86 linux
  • tech support
Version D 1.075 Aug 2, 2012

New/Changed Features

  • Bugzilla 8127: dmd link library paths not given precedence over gcc defaults

Bugs Fixed

  • Bugzilla 1175: nested class inheritance
  • Bugzilla 1780: Type tuple deduction failure for class templates
  • Bugzilla 2328: setTypeInfo in gc.d backwards.
  • Bugzilla 2472: Delegates are not lvalue.
  • Bugzilla 2962: ICE(glue.c) or bad codegen passing variable as template value parameter
  • Bugzilla 3574: post-condition in void main() is not evaluated if there is no return statement
  • Bugzilla 3608: Allow isExpression and templates to capture template parameters and FQN of template
  • Bugzilla 4024: Last catch only accepts block statement
  • Bugzilla 4155: return of NaN to temporary fails equality test
  • Bugzilla 4288: Error on passing delegate to C linkage function
  • Bugzilla 4364: ICE(class.c) compiling a struct def named 'Object' followed by a class definition
  • Bugzilla 4583: PIC code not working: EBX register set incorrectly
  • Bugzilla 4785: auto return of a function with in contract
  • Bugzilla 4967: member default initializers not working in static struct initializers
  • Bugzilla 5039: Cannot use invariant() with auto methods
  • Bugzilla 5809: [64 bit] wrong code for *p==0, when widening conversion occurs
  • Bugzilla 6189: [64bit] optimizer: register content destroyed in function prolog
  • Bugzilla 6475: template identifier is not a member of alias
  • Bugzilla 6591: di header generation loses selective import symbols
  • Bugzilla 6612: Associative arrays with associative array keys literals
  • Bugzilla 6758: std.c.stdarg problems with 8 or more integer arguments on x86_64
  • Bugzilla 6891: template with uint value parameter causes several issues
  • Bugzilla 7396: Indicate default alignment with 0.
  • Bugzilla 7453: Can't return value from within opApply
  • Bugzilla 7478: stack overflow compiling with -deps -release -inline -noboundscheck
  • Bugzilla 7537: File.tmpfile requires administrator rights on Windows
  • Bugzilla 7581: Compiler uses wrong instructions to move complex value from ST to xmm registers
  • Bugzilla 7750: while(true) loop with try/catch block causes segfault
  • Bugzilla 7770: __dollar cannot be read at compile time
  • Bugzilla 7784: ICE with self-referencing literals
  • Bugzilla 7793: static assert( void_function() ) gives misleading error message
  • Bugzilla 7851: Internal error: e2ir.c 688
  • Bugzilla 7880: [CTFE] cast from void array allowed with different results than at runtime
  • Bugzilla 7893: Spec completely wrong for D variadic arguments on 64 bits
  • Bugzilla 7894: [CTFE] - goto within ForStatement restarts loop
  • Bugzilla 7907: [ICE] invalid expression on template argument crashes dmd
  • Bugzilla 7911: Nested static if failing to execute
  • Bugzilla 7931: Error message with _error_ with var[1,2]
  • Bugzilla 7932: Corrupted argument inside out contract in x86_64
  • Bugzilla 7933: Illegal interaction of templates
  • Bugzilla 7950: Type tuples are incorrectly flattened in base type list of interface
  • Bugzilla 7974: forward reference of mixin declaration
  • Bugzilla 7987: [CTFE] cannot compare arrays of slices
  • Bugzilla 8002: Excess initial errors when passing template args to non-templated struct
  • Bugzilla 8016: Methods defined in external object files when template alias parameter is involved
  • Bugzilla 8032: `mixin template` before virtual method with same method causes an error
  • Bugzilla 8060: xmmstore cannot allocate store for optimized operation that uses int and floats
  • Bugzilla 8066: ICE on missing return statement if invariant is present
  • Bugzilla 8069: incorrect ambiguous virtual function error
  • Bugzilla 8073: Regression (git) Error: undefined identifier __result
  • Bugzilla 8089: Importing package as module causes segfault
  • Bugzilla 8091: Optimizer generates wrong code when reducing comparisons
  • Bugzilla 8094: Static if matching using alias parameter in template fails
  • Bugzilla 8095: [64 bit] Wrong code generation with spilled register, -m64 -O
  • Bugzilla 8125: TypeInstance dedunction problem
  • Bugzilla 8147: Blah!R.init now requires parens - (Blah!R).init
  • Bugzilla 8188: need this to access member when mixining in a function
  • Bugzilla 8190: Externally defined struct error message
  • Bugzilla 8199: stack is not aligned in finally block
  • Bugzilla 8216: CTFE should allow 'pointer is inside range' comparisons
  • Bugzilla 8237: Error message with _error_ when using failed type inference in template parameter
  • Bugzilla 8276: [CTFE] ICE when reading variable from nested function
  • Bugzilla 8283: ICE(cod1.c): returning struct with constructor as member of another struct
  • Bugzilla 8423: Wrong code for bool parameter in 5th integer register.
  • Bugzilla 8437: [2.060 beta] static struct no size yet for forward reference
  • Bugzilla 8454: [ICE] (backend\cg87.c 3497) with cdouble and sqrt
Version D 1.074 Apr 12, 2012

New/Changed Features

  • Add predefined Ddoc macro SRCFILENAME
  • Added std.c.stdint

Bugs Fixed

  • Bugzilla 176: [module] message "module and package have the same name"
  • Bugzilla 783: Cannot use an array w/ const or variable index as new[] size argument.
  • Bugzilla 977: Expressions inside a struct or array initializer get wrong line number
  • Bugzilla 3354: invalid number of args accepted for 1/2 arg floating point instructions
  • Bugzilla 3509: Cannot forward reference a template mixin's members in a compile-time context
  • Bugzilla 3510: Cannot forward reference a templated type from within a template mixin
  • Bugzilla 3559: DMD 1.048+ fails to take function pointer from overloaded member functions
  • Bugzilla 3630: bad error location in "has no effect in expression" error
  • Bugzilla 3682: Regression(2.038) is expression fails to match types
  • Bugzilla 3812: Missing line number for implicit cast of variadic function to array
  • Bugzilla 3822: Invalid optimization of alloca called with constant size
  • Bugzilla 4241: duplicate union initialization error doesn't give a file location
  • Bugzilla 4269: Regression(2.031): invalid type accepted if evaluated while errors are gagged
  • Bugzilla 4820: Regression(1.058, 2.044) in DStress caused by changeset 452
  • Bugzilla 4993: Temporary values and opIndexAssign
  • Bugzilla 5181: Excess cast on in-place operation op= involving conversion
  • Bugzilla 5554: [qtd] Covariance detection failure
  • Bugzilla 5879: Not all frontend errors use stderr
  • Bugzilla 6391: Line-less error when passing the '.im' of floating pointer value by reference
  • Bugzilla 6438: [CTFE] wrong error "value used before set" when slicing =void array
  • Bugzilla 6699: More cases of __error in error messages
  • Bugzilla 6681: struct constructor call is converted to struct literal that breaks union initialization
  • Bugzilla 7380: Crash trying to use address of variable in struct constructor at module level
  • Bugzilla 7399: Broken import statement in trySemantic() causes silent compiler error
  • Bugzilla 7406: tuple foreach doesn't work with mixed tuples
  • Bugzilla 7462: Error message with _error_ in overridden function
  • Bugzilla 7463: Duplicated error message with bad template value parameter
  • Bugzilla 7473: [CTFE] Non-ref argument behaves as if it's a ref argument
  • Bugzilla 7493: Initialization of void[][N]
  • Bugzilla 7527: [CTFE] Segfault when slicing a pointer at compile time
  • Bugzilla 7536: ctfeAdrOnStack triggered
  • Bugzilla 7544: ICE(interpret.c) Catching an exception with a null catch block
  • Bugzilla 7547: -deps output lists object as a top level module
  • Bugzilla 7550: Missing AVX instruction VPMULDQ
  • Bugzilla 7557: Sea of errors after template failure
  • Bugzilla 7563: Class members with default template arguments have no type
  • Bugzilla 7568: pragma(msg) segfaults with an aggregate including a class.
  • Bugzilla 7592: Conversion from ireal to ifloat broken when using xmm
  • Bugzilla 7633: Missing CTFE error message
  • Bugzilla 7639: Undefined enum AA key crashes compiler
  • Bugzilla 7641: std.typecons.Proxy incorrectly allows implicit conversion to class
  • Bugzilla 7667: ICE(interpret.c): 'ctfeStack.stackPointer() == 0'
  • Bugzilla 7681: Regression(2.059head):ICE:opCatAssign(delegate) to undefined identifier
  • Bugzilla 7694: Internal error: e2ir.c 1251 when calling member function inside struct via alias param
  • Bugzilla 7699: Cannot get frame pointer to in contract when compiling with -inline
  • Bugzilla 7735: Functions with variadic void[][]... arguments corrupt passed data
  • Bugzilla 7745: Regression (1.x git-415e48a) Methods defined in external object files when a pointer to it is taken
  • Bugzilla 7754: static this() in template is stripped during header gen
  • Bugzilla 7755: regression(2.059head): ICE in glue.c
  • Bugzilla 7768: More readable template error messages
  • Bugzilla 7781: [CTFE] Segmentation fault on 'mixin({return;}());
  • Bugzilla 7782: [ICE] With wrong import syntax
  • Bugzilla 7785: [CTFE] ICE when slicing pointer to variable
  • Bugzilla 7786: dmd crashes with invalid module name
  • Bugzilla 7789: [CTFE] null pointer exception on setting array length
  • Bugzilla 7794: Sea of errors when calling regex() after compile error
  • Bugzilla 7812: Segfault on invalid code during template match deduction with errors gagged
  • Bugzilla 7814: Regression(2.059head) ICE(tocsym.c) using scope(failure) within foreach-range
  • Bugzilla 7817: opAssign to in declaration broken in dmd 1.074 beta1
Version D 1.073 Feb 8, 2012

New/Changed Features

  • Convert to -shared dmd switch instead of -dylib
  • Better use of XMM registers in OS X 32 bit target.
  • Add inline assembler support for AVX instructions (64 bit targets only).

Bugs Fixed

  • Bugzilla 516: Mutually calling constructors allowed
  • Bugzilla 664: is(func T == function) ignores variadic arguments
  • Bugzilla 678: Compiler accepts, for a function T[] t(), t().ptr but not t.ptr
  • Bugzilla 796: Asserting a null object reference throws AssertError Failure internal\invariant.d(14) or Access Violation
  • Bugzilla 949: Wrong spec/compiler behaviour for Strings, Integers and Floats
  • Bugzilla 955: Passing arguments into functions - in, out, inout, const, and contracts
  • Bugzilla 1313: out/body disables escape analysis
  • Bugzilla 1521: Ambiguous documentation
  • Bugzilla 1563: dynamic cast is not always performed
  • Bugzilla 1570: Wrong return for address operator
  • Bugzilla 1918: __traits(getVirtualFunctions) returns final functions
  • Bugzilla 1920: Class documentation incomplete
  • Bugzilla 1943: Templates can't take function pointer parameters
  • Bugzilla 2106: export class doesn't affect, what is exported
  • Bugzilla 2351: enum with no members allowed
  • Bugzilla 2382: spec is not clear on what is allowed as global/static initializers
  • Bugzilla 2387: Static array terminology
  • Bugzilla 2417: [module] protected base member is not available via base handle in a derived class if it is defined in a separate module
  • Bugzilla 2483: DMD allows assignment to a scope variable
  • Bugzilla 2494: describe explicit casting of arrays
  • Bugzilla 2495: const syntax for member functions needs better description
  • Bugzilla 2497: delete and null relationship needs more details
  • Bugzilla 2639: Hex and octal string values not completely specified
  • Bugzilla 2819: array.sort segfaults if array length >=0x8F_FFFF
  • Bugzilla 2894: abstract classes sometimes allow non-abstract bodyless functions
  • Bugzilla 3084: Formatting of lazy in parameters section
  • Bugzilla 3092: Indexing a tuple produces a tuple containing the indexed element
  • Bugzilla 3111: 'mangleof' can't be member of a struct not documented
  • Bugzilla 3187: Nested foreach over opApply doesn't work
  • Bugzilla 3204: Document global properties
  • Bugzilla 3265: .classinfo for Interface-typed reference does not return instance's ClassInfo
  • Bugzilla 3492: Can't overload nested functions
  • Bugzilla 3578: Impossible to run a struct invariant using assert(s)
  • Bugzilla 3735: op=
  • Bugzilla 3757: Overloading const function with overridden non-const function results in seg fault.
  • Bugzilla 3777: size_t is undefined
  • Bugzilla 3783: Text inconsistent with EscapeSequence rules
  • Bugzilla 3787: clarification: assigment to 'this'
  • Bugzilla 3791: Reference anonymous nested classes when describing new expressions
  • Bugzilla 3838: PrimaryExpression rule doesn't permit module scope template instances
  • Bugzilla 3886: Bad example of definition file for DLLs
  • Bugzilla 3906: Undefined struct and union declarations are not documented
  • Bugzilla 3954: DeclDef rule is missing TemplateMixinDeclaration
  • Bugzilla 3988: Provide canonical example for operator overloading
  • Bugzilla 4135: Regression(1.034): ICE(statement.c): mixin in bad foreach, D1 only
  • Bugzilla 4180: D DWARF extensions conflict with DWARF-4
  • Bugzilla 4235: !in not working (D1)
  • Bugzilla 4371: segfault(template.c) template tuple in is() expression
  • Bugzilla 4413: typeof(this) doesn't work in method template signature
  • Bugzilla 4523: [tdpl] .remove method for Associative Arrays returns void in all cases
  • Bugzilla 4545: Alias to members possible without "this" instance
  • Bugzilla 4647: [tdpl] Cannot explicitly call final interface method, ambiguous calls allowed
  • Bugzilla 4711: Incorrect handling of && operator with void operand
  • Bugzilla 4887: Right-shifting by 32 is allowed and broken
  • Bugzilla 4956: remove direct references to gcc from linux.mak
  • Bugzilla 5023: Docs about order of execution of invariant and pre/post conditions
  • Bugzilla 5111: Static function-level variables are not in the language spec.
  • Bugzilla 5114: Too many error messages
  • Bugzilla 5132: ~ unary operator silently different from C
  • Bugzilla 5138: Special token sequence
  • Bugzilla 5337: Documentation regarding interfacing with C does not account for TLS differences
  • Bugzilla 5476: spec: attributes have an optional else clause
  • Bugzilla 5527: Bug in http://www.digitalmars.com/d/2.0/ctod.html#closures
  • Bugzilla 5648: dmd command line option list inconsistencies
  • Bugzilla 5715: Contradiction in spec: meaning of variable.init
  • Bugzilla 5796: ICE with pragma(msg, ...) after missing ';' in a template
  • Bugzilla 5820: Documentation states string literals can implicitly convert to char*
  • Bugzilla 5841: alias grammar is incorrect
  • Bugzilla 6013: private ignored for aliases
  • Bugzilla 6037: [CTFE] recursive ref parameters evaluated incorrectly
  • Bugzilla 6451: [64bit] ICE(expression.c:4434): SymbolExp::SymbolExp(Loc, TOK, int, Declaration*, int): Assertion 'var' failed
  • Bugzilla 6504: Regression(2.041): "str" ~ [arr] allows string literal to be modified
  • Bugzilla 6701: template specialization resolution failure
  • Bugzilla 6933: Segfault(declaration.c) using struct with destructor in CTFE
  • Bugzilla 6934: [CTFE] can't use $ in a slice of an array passed by ref
  • Bugzilla 6964: Error message with __error: static assert(undefined+1)
  • Bugzilla 6968: Segmantation fault, if exclamation mark absent
  • Bugzilla 6971: [lex.dd] Type of string literals are outdated
  • Bugzilla 6984: CTFE generates a torrent of spurious errors, if there was a previous error
  • Bugzilla 6985: [CTFE] Non-constant case expressions can't be interpreted
  • Bugzilla 6995: [CTFE] can't interpret static template method
  • Bugzilla 7011: No line number error for vector power
  • Bugzilla 7043: CTFE: ICE illegal reference value 0LU, only with -inline
  • Bugzilla 7073: Parsing of class-returning varargs function inside module ctor fails
  • Bugzilla 7108: ICE: TraitsExp::semantic(Scope*) 2.056 -> 2.057 regression - segfault
  • Bugzilla 7120: Scope Delegates + Delegate Literals
  • Bugzilla 7123: static assert(is(typeof(toDelegate(&main)))) is false
  • Bugzilla 7127: Const-related infinite recursion in DWARF generation
  • Bugzilla 7143: [CTFE] cannot compare class references with "is"
  • Bugzilla 7144: [CTFE] base class does not call overridden members
  • Bugzilla 7154: [CTFE] failing downcast causes error
  • Bugzilla 7158: [CTFE] ICE(interpret.c) calling a class member using a dotvar expression
  • Bugzilla 7162: [CTFE] "bool || void" expression crashes dmd
  • Bugzilla 7165: [CTFE] ice converting null pointer to bool with constant member function
  • Bugzilla 7166: Internal error: ../ztc/cgxmm.c 60
  • Bugzilla 7173: dmd: glue.c:1065: virtual unsigned int Type::totym(): Assertion `0' failed.
  • Bugzilla 7178: Segfault with import of invalid template
  • Bugzilla 7185: [CTFE] ICE on changing char array length
  • Bugzilla 7187: Regression(head 12d62ca5): [CTFE] ICE on slicing
  • Bugzilla 7188: "import phobos;" crashes DMD
  • Bugzilla 7189: inline failed
  • Bugzilla 7190: Tuple length incorrect
  • Bugzilla 7194: [CTFE] Incorrect behaviour with pointers as local struct variable
  • Bugzilla 7197: enum string doesn't work with CTFE
  • Bugzilla 7216: [CTFE] Can't call struct member function using pointer field
  • Bugzilla 7217: [CTFE] ICE on accessing struct array field
  • Bugzilla 7218: Nested function with contract is rejected
  • Bugzilla 7228: MOVDQ2Q instruction is emitted with swapped register indices
  • Bugzilla 7231: Segfault using opDispatch with property notation
  • Bugzilla 7232: Warning: statement is not reachable has no line number
  • Bugzilla 7239: C style struct initialization doesn't work with aliases
  • Bugzilla 7245: [CTFE] Address of ref foreach parameter changes to point after array
  • Bugzilla 7248: [CTFE] Stack overflow on using struct filed pointer with address of array element
  • Bugzilla 7266: [CTFE] Assign to ref param (that's taken from struct member) is noop
  • Bugzilla 7277: [CTFE ICE] Assertion failure: 'thisval' on line 1690 in file 'interpret.c'
  • Bugzilla 7285: Implicit fixed-size array cast
  • Bugzilla 7309: [2.058] Regression caused by new inlining code
  • Bugzilla 7335: sometimes the OUT - block have undefined class members-acces
  • Bugzilla 7351: Possible asm bug: bad type/size of operands 'xadd'
  • Bugzilla 7359: Template function with typesafe variadic rejects more than one string arguments
  • Bugzilla 7367: wrong char comparison result
  • Bugzilla 7373: (Regression git) Renamed imports conflict with other implicitly imported symbols
  • Bugzilla 7375: Regression(2.057): Invalid downcast permitted with derived/aliased template classes
  • Bugzilla 7377: Compiler segfault in: TemplateMixin::hasPointers()
  • Bugzilla 7383: Blank lines in code sections cause premature section termination
  • Bugzilla 7419: [2.058/CTFE] Constructor of struct is overwritten inside a unittest with -inline
  • Bugzilla 7435: Regression(master):dmd crashes when 'scope(failure) debug ...' without -debug option.
Version D 1.072 Dec 10, 2011

New/Changed Features

  • Better use of XMM registers in 64 bit targets.
  • Add Mach-O 64 bit support for obj2asm and dumpobj
  • Add OSX 64 bit target
  • classes, interfaces, and exceptions are supported in CTFE

Bugs Fixed

  • Bugzilla 2532: '=' does not give a boolean result
  • Bugzilla 2856: static opIndex does not compile for a templated struct/class
  • Bugzilla 3990: Deferencing a dynamic array as pointer
  • Bugzilla 4047: [CTFE] class/struct heap allocation
  • Bugzilla 4511: Contravariance problem
  • Bugzilla 4583: PIC code not working: EBX register set incorrectly
  • Bugzilla 5311: Pure is broken when accessing globals / static data through instance reference
  • Bugzilla 5364: optimizer kills high dword of -1
  • Bugzilla 6077: CTFE: Cannot append null array to null array.
  • Bugzilla 6354: Optimizer bug on x86_64: Bitshift optimized out when foreach and scope(failure) are used
  • Bugzilla 6416: [CTFE] Declaration static struct is not yet implemented in CTFE
  • Bugzilla 6522: [CTFE] Problem with opAssign call in foreach(ref)
  • Bugzilla 6603: [CTFE] Can't call through a manifest constant function pointer
  • Bugzilla 6792: [CTFE] ICE with pointer cast of indexed array
  • Bugzilla 6800: [CTFE] dangerous pointer casts should be rejected
  • Bugzilla 6816: [CTFE] nested function can't access this
  • Bugzilla 6817: [CTFE] Error on interpreting inlined IfStatement
  • Bugzilla 6851: [CTFE] Cannot deref pointer passed by argument
  • Bugzilla 6859: Segfault when abstract method uses with contract.
  • Bugzilla 6868: IsExp + incorrect static array type = error
  • Bugzilla 6877: [XMM] regression, clobbered float value
  • Bugzilla 6879: The difference of between template matching and IsExp
  • Bugzilla 6881: [XMM] ICE with painted float
  • Bugzilla 6885: [CTFE] wrong code with dynamically allocated 2D array
  • Bugzilla 6886: [CTFE] ICE(interpret.c) new array with initializer
  • Bugzilla 6901: wrong error "override cannot be applied to variable" in CTFE forward reference
  • Bugzilla 6910: __traits(hasMember, "") does not work, if template has alias param
  • Bugzilla 6919: [CTFE] Cannot get effect to local variable through its pointer
  • Bugzilla 6972: [CTFE] ICE with ubyte/=uint
  • Bugzilla 6997: 64bit optimizer bug
  • Bugzilla 7004: Iterating tuple with index which explicitly typed as size_t causes an error
  • Bugzilla 7026: 64 bit optimizer bug
  • Bugzilla 7028: Fails to save FPU regs when executing finally block
Version D 1.071 Oct 26, 2011

New/Changed Features

  • add -gs compiler switch
  • Bugzilla 6752: Add separate option to control stack frame generation

Bugs Fixed

  • Bugzilla 546: Error message for accessing a deprecated variable is doubled
  • Bugzilla 1891: Array-concatenation of T* and T*[] produces corrupted result
  • Bugzilla 1993: Error calling vararg delegate with null
  • Bugzilla 2315: DMD Stack Overflow on unwanted ctfe recursion
  • Bugzilla 2553: Excess attribute propagation for interfaces
  • Bugzilla 2740: Template Mixins do not work as advertised
  • Bugzilla 2953: tuple.length rejected as a tuple parameter in a static foreach
  • Bugzilla 3069: Array literals do not implicitly cast to void[]
  • Bugzilla 3133: Compiler does not check that static array casts are legal
  • Bugzilla 4022: [CTFE] AA get
  • Bugzilla 4197: ICE(glue.c): error in forward-referenced in/out contract
  • Bugzilla 4206: type accepted as enum initializer
  • Bugzilla 4237: Typedefs of the same name cause initializer conflict
  • Bugzilla 4269: Regression(2.031): invalid type accepted if evaluated while errors are gagged
  • Bugzilla 4284: empty string[] alias lacks .length in a template
  • Bugzilla 5453: ICE(statement.c): invalid switch statement forward referenced by CTFE
  • Bugzilla 5696: Templates typetuple iteration
  • Bugzilla 5932: Internal error: s2ir.c 339
  • Bugzilla 6073: Cannot pass __traits(parent, ...) as a template parameter if it is a module
  • Bugzilla 6084: Impossible to instantiate local template with TypeTuple-foreach iterator variable.
  • Bugzilla 6087: typeof(this) doesn't work outside member function
  • Bugzilla 6139: Duplicate error message on compile-time out of bounds array index
  • Bugzilla 6296: ICE(glue.c): invalid template instantiated in is(typeof()).
  • Bugzilla 6584: ICE on large version number/debug level
  • Bugzilla 6599: Segfault: invalid expression in initializer
  • Bugzilla 6661: Templates instantiated only through is(typeof()) shouldn't cause errors
  • Bugzilla 6665: Regression(2.055) ICE(cg87.c): static double inside closure
  • Bugzilla 6672: [CTFE] ICE on compile time std.algorithm.sort
  • Bugzilla 6693: [CTFE] Cannot set value to nested AA
  • Bugzilla 6695: typeof(this) does not take into account const/immutable attributes inside member functions
  • Bugzilla 6721: [CTFE] Cannot get pointer to start of char[]
  • Bugzilla 6727: [CTFE] ICE(interpret.c): assignment from string literal.dup.ptr
  • Bugzilla 6733: Regression(2.054) ICE(cod2.c) pure nothrow func with side-effect parameters
  • Bugzilla 6739: [CTFE] Cannot set a value to an outer AA of a nested AA
  • Bugzilla 6749: [CTFE] problem with array of structs
  • Bugzilla 6751: [CTFE] ref argument of AA doesn't work
  • Bugzilla 6765: [CTFE]: AA.length doesn't compile when AA is null
  • Bugzilla 6769: [CTFE] AA.keys doesn't compile when -inline is used
  • Bugzilla 6775: Regression(2.054) ICE(glue.c) template parameter deduction with errors gagged
  • Bugzilla 6813: Yet another "cannot get frame pointer" error
  • Bugzilla 6825: Regression(2.055+): Address of templated method incorrectly taken
Version D 1.070 Sep 4, 2011

New/Changed Features

  • Add support for Mac OS X 10.7 Lion
  • Add protection to json output
  • Add SSE4.1 and SSE4.2 assembly instructions

Bugs Fixed

  • Bugzilla 1471: Linker error on template function. Error 42: Symbol Undefined ...
  • Bugzilla 1567: call to private super-constructor should not be allowed
  • Bugzilla 1684: offsetof does not work, adding cast is workaround
  • Bugzilla 1904: wrong protection lookup for private template functions
  • Bugzilla 2156: [] and null should be accepted where a compile-time string is required
  • Bugzilla 2246: Regression(2.046, 1.061): Specialization of template to template containing int arguments fails
  • Bugzilla 2355: is() doesn't resolve aliases before template matching
  • Bugzilla 2634: Function literals are non-constant.
  • Bugzilla 2774: Functions-as-properties makes it impossible to get the .mangleof a function
  • Bugzilla 2941: Wrong code for inline asm because CPU type is set too late
  • Bugzilla 3512: dchar iteration over string in CTFE fails
  • Bugzilla 4021: [CTFE] AA rehash
  • Bugzilla 4444: Cannot index built-in array with expression tuple
  • Bugzilla 4460: Regression(2.036) ICE(e2ir.c) when compiling foreach over associative array literal
  • Bugzilla 4682: [CTFE] Run-time Vs Compile-time of int.min % -1
  • Bugzilla 4837: ICE(constfold.c) CTFE with >>>=
  • Bugzilla 5046: Wrong type of implicit 'this' in struct/class templates
  • Bugzilla 5239: optimizer misreports an used before set error
  • Bugzilla 5585: bad debug line number info for return statements with enumerator expressions
  • Bugzilla 5790: 'Error: variable result used before set' when -release -inline -O
  • Bugzilla 5799: Address-of operator fails on nested conditional operator expression
  • Bugzilla 5953: Too many trailing commas are accepted
  • Bugzilla 6097: SSSE3 not working with MMX instructions
  • Bugzilla 6215: LLVM-compiled DMD segfaults due to mem.c alignment issues
  • Bugzilla 6250: [CTFE] Crash when swapping two pointers to arrays.
  • Bugzilla 6270: XMMREGS not preserved on indirect function call
  • Bugzilla 6276: [CTFE] Strange behavior of using ~= operator twice
  • Bugzilla 6280: [CTFE] Cannot put 'in' expression of AA in an 'if' condition
  • Bugzilla 6281: [CTFE] A null pointer '!is null' returns 'true'.
  • Bugzilla 6282: [CTFE] ICE when dereferencing a pointer to reference type from 'in' of an AA
  • Bugzilla 6283: [CTFE][Regression 2.054] Failed to assign to AA using a constness-changed array as key
  • Bugzilla 6306: Regression(2.054): [CTFE] Strange behavior of indirect recursive call in CTFE
  • Bugzilla 6331: [CTFE] Cannot evaluate SliceExp on if condition
  • Bugzilla 6337: [CTFE] ICE when touching member variable of struct during CTFE
  • Bugzilla 6344: [CTFE] Assertion Failure in interpret.c when create an empty slice from null pointer
  • Bugzilla 6355: Template constructor cannot initialize non-mutable field
  • Bugzilla 6374: [CTFE] Cannot subscript using pointer to array
  • Bugzilla 6375: [CTFE] Segfault when using std.array.appender with an initial array
  • Bugzilla 6386: [CTFE] ICE on pointer casting
  • Bugzilla 6399: [CTFE] struct member array.length -= x doesn't work, while array[0..$-x] works
  • Bugzilla 6418: [CTFE] Cannot call a struct member function with name 'length'.
  • Bugzilla 6429: Nested function error in reduce
  • Bugzilla 6491: Fully qualified values in default arguments of non-template functions are generated with an extra 'module' keyword
  • Bugzilla 6505: Wrong code for expression involving 8 floats, only with -O
  • Bugzilla 6512: [CTFE] new T[][] doesn't work
  • Bugzilla 6516: Regression(2.055 beta) [CTFE] ICE(constfold.c) involving new dchar[]
  • Bugzilla 6558: [CTFE] UTF-decoding foreach gives wrong index (1-indexed)
  • Bugzilla 6563: wrong code when using at least 8 XMM regs
  • Bugzilla 6601: Regression(2.053): CTFE segfault taking address of function template
  • Bugzilla 6602: Invalid template instantiations leaked by is(typeof())/__traits(compiles, )/Type::trySemantic
Version D 1.069 Jul 10, 2011

New/Changed Features

  • Allow labelled break and continue in CTFE
  • Pointers are now supported in CTFE
  • Heap-allocated structs are now supported in CTFE
  • Added SSSE3 instructions to inline assembler
  • Change win32 dmd to not emit a map file unless asked for with -map

Bugs Fixed

  • Bugzilla 693: 'this' can't be used as an alias parameter for a mixin
  • Bugzilla 1373: typeof(func).stringof fails when func has parameters.
  • Bugzilla 1570: Wrong return for address operator
  • Bugzilla 2180: filename error with #line
  • Bugzilla 2842: std.file.listdir on OSX produces invalid UTF-8 sequence
  • Bugzilla 3445: partial fix
  • Bugzilla 3722: A method without an in contract should always succeed, even if overridden
  • Bugzilla 4063: [CTFE] key not found in AA gives bad error message
  • Bugzilla 4065: [CTFE] AA "in" operator doesn't work
  • Bugzilla 4107: Duplicate documentation for member function templates
  • Bugzilla 4448: [CTFE] labeled break doesn't work in CTFE
  • Bugzilla 4494: ICE(cod1.c) Array literal filled with results of void function
  • Bugzilla 4633: typeof({return 1;}()) declaration fails if inside main
  • Bugzilla 4745: Non-uniform handling of commas in static initialization of structs
  • Bugzilla 4910: [CTFE] Cannot evaluate a function that has failed at once
  • Bugzilla 4963: ICE(type.c:320) for struct append where T.sizeof < 3
  • Bugzilla 4969: nothrow check can't handle multiple catches
  • Bugzilla 5086: Regression(1.061): Stack overflow with recursive alias declaration
  • Bugzilla 5258: [CTFE] Stack overflow with struct by ref
  • Bugzilla 5396: [CTFE] Invalid code with nested functions in CTFE
  • Bugzilla 5615: [CTFE] std.string.indexOf broken at compile time
  • Bugzilla 5633: [CTFE] ICE(constfold.c): is expression with struct, struct pointer, array literal...
  • Bugzilla 5676: [CTFE] segfault using tuple containing struct that has opAssign
  • Bugzilla 5682: [CTFE] Silently wrong result possibly related to operator overloading and expression order
  • Bugzilla 5682: Wrong CTFE with operator overloading
  • Bugzilla 5708: [CTFE] Incorrect string constant folding with -inline
  • Bugzilla 5845: Regression(2.041) [CTFE] "stack overflow" with recursive ref argument
  • Bugzilla 5936: Invalid code with nested functions in CTFE
  • Bugzilla 5946: failing lookup 'this' from function in template
  • Bugzilla 5963: iasm does not accept 64bit integer literal
  • Bugzilla 5885: wrong codegen for OPu32_d
  • Bugzilla 6001: [CTFE] ICE(interpret.c) mutating ref array
  • Bugzilla 6015: [CTFE] Strange behavior of assignment appears in a situation
  • Bugzilla 6049: [CTFE] Array literals of structs with invariant() are wrong
  • Bugzilla 6052: [CTFE] Struct elements in an array are treated like reference type
  • Bugzilla 6053: [CTFE] Two ICEs involving pointers (dereference and assign; pointer variable on stack)
  • Bugzilla 6054: [CTFE] ICE when returning a returned compile-time associative array containing a key of an idup-ed array literal
  • Bugzilla 6072: [CTFE] Regression(git master): Cannot declare variable inside an 'if' condition
  • Bugzilla 6077: [CTFE] Cannot append null array to null array.
  • Bugzilla 6078: [CTFE] ICE on foreach over array struct member which is null
  • Bugzilla 6079: [CTFE] Array index out of bound detection is off-by-one
  • Bugzilla 6090: DDoc parenthesis escape issues.
  • Bugzilla 6100: [CTFE] Regression: struct return values wrong if used in array initializer
  • Bugzilla 6120: [CTFE] ICE on calling constructor of template struct with -inline in function/delegate literal.
  • Bugzilla 6123: [CTFE] Cannot call a template member method inside delegate/function literal with -inline.
  • Bugzilla 6137: [CTFE] Foreach on semantically wrong initialized array crashes the compiler
  • Bugzilla 6164: [CTFE] Local arrays in a recursive local function behave funny
  • Bugzilla 6242: Disallow inoperant "in" contracts
Version D 1.068 May 12, 2011

New/Changed Features

  • Added 64 bit tools to Linux
  • Renamed linux/bin to linux/bin32, added linux/bin64
  • Bugzilla 4833: dmd -od doesn't make it to optlink's command line for map files
  • Added cmpxchg16b, 64 bit bswap and movq instructions to IASM

Bugs Fixed

  • Bugzilla 937: C-style variadic functions broken
  • Bugzilla 1330: Array slicing does not work the same way in CTFE as at runtime
  • Bugzilla 1389: Can't use mixin expressions when start of a statement.
  • Bugzilla 2436: Unexpected OPTLINK termination EIP = 00425303 with /co
  • Bugzilla 2990: TypeInfo.init() returns invalid array
  • Bugzilla 3214: Incorrect DWARF line number debugging information on Linux
  • Bugzilla 3372: optlink silently mistreats object files with more than 16384 symbols
  • Bugzilla 3779: ["123"][0][$-1] causes __dollar unresolved in compile-time.
  • Bugzilla 3792: Regression(1.053) "non-constant expression" for a template inside
  • Bugzilla 3801: CTFE: this.arr[i] cannot be evaluated at compile time for structs
  • Bugzilla 3809: Struct initializers apparently always CTFE'd
  • Bugzilla 3835: ref foreach does not work in CTFE
  • Bugzilla 4001: const variables should be readable inside CTFE
  • Bugzilla 4048: [CTFE] struct initializer: missing line number in error message
  • Bugzilla 4050: [CTFE] array struct member slice update
  • Bugzilla 4051: [CTFE] array struct member item update
  • Bugzilla 4140: Error: non-constant expression "hello"[1u..__dollar]
  • Bugzilla 4275: Unexpected optlink termination when 'export' attribute is missing
  • Bugzilla 4543: Regression(1.054, 2.038) typedef circular definition and segfault
  • Bugzilla 4815: CodeView: Global and Static symbols should have unmangled names
  • Bugzilla 4817: CodeView: Enum members should have simple names
  • Bugzilla 4917: Symbol conflict error message refers to aliased symbol instead of the alias
  • Bugzilla 5147: [CTFE] Return fixed-sized matrix
  • Bugzilla 5362: checking $ in bracket is broken.
  • Bugzilla 5647: [64-bit] Valgrind complains about illegal instruction
  • Bugzilla 5664: Cannot compile static synchronized member function.
  • Bugzilla 5670: Optlink 8.00.11 crash
  • Bugzilla 5671: Issue 5671 - CTFE string concat problem
  • Bugzilla 5672: ICE(cod2.c): incorrect optimization of (long &1) == 1
  • Bugzilla 5680: wrong calling convention on wsprintfA/W
  • Bugzilla 5694: va_arg doesn't work with idouble and ifloat
  • Bugzilla 5706: Incorrect opcode prefix generated for x86_64 inline assembly
  • Bugzilla 5708: Incorrect string constant folding with -inline
  • Bugzilla 5717: 1.067 regression: appending Unicode char to string broken
  • Bugzilla 5722: Regression(2.052): Appending code-unit from multi-unit code-point at compile-time gives wrong result.
  • Bugzilla 5735: non-scalar types implicitly converted to boolean.
  • Bugzilla 5740: Unable to use "this" pointer in inline assembly
  • Bugzilla 5741: Add the SYSCALL and SYSRET opcodes to the inline assembler
  • Bugzilla 5840: Cannot assign to an array member of struct in CTFE
  • Bugzilla 5852: CTFE: wrong code for string[] ~= const(string)
  • Bugzilla 5858: Import not acctept const string as arguments
  • Bugzilla 5865: __dollar cannot be read at compile time
  • Bugzilla 5916: DMD: bad message for incorrect operands error
  • Bugzilla 5966: [2.053 beta][CTFE] Stack overflow on trivial func
  • Bugzilla 5972: CTFE: Can't assign to elements of arrays of slices
  • Bugzilla 5975: [2.053 beta][CTFE] ICE: 'global.errors' on line 1416 in file 'constfold.c'
  • Bugzilla 5976: "variable used before set" with foreach with ref + scope(failure) + structure method + -O -inline
  • Fix spelling of cmpxchgb8
Version D 1.067 Feb 17, 2011

New/Changed Features

  • 64 bit support for Linux
  • Support HTML5 entities
  • FreeBSD version upgraded to FreeBSD 8.1

Bugs Fixed

  • Bugzilla 190: Cannot forward reference typedef/alias in default value for function parameter
  • Bugzilla 1914: Array initialisation from const array yields memory trample
  • Bugzilla 3198: wrong initializer for structs arrays
  • Bugzilla 3681: ICE(go.c): when function takes too long to optimize, only with -O.
  • Bugzilla 4245: Declaring conflicting symbols in single function scope allowed
  • Bugzilla 4379: ICE(blockopt.c): foreach over huge tuple, only with -O
  • Bugzilla 4389: ICE(constfold.c, expression.c), or wrong code: string~=dchar in CTFE
  • Bugzilla 4486: CodeView debug info should contain absolute path names
  • Bugzilla 4753: fail_compilation/fail116.d sends dmd into a loop, exhausting memory
  • Bugzilla 4878: Ddoc: Default arguments can break Ddoc output
  • Bugzilla 4973: map file with spaces in file name passed without quotes to linker
  • Bugzilla 5015: Regression(1.061): Cyclic import breaks is() in a static if
  • Bugzilla 5090: ICE(todt.c) struct literal initializing zero length array
  • Bugzilla 5105: Member function template cannot be synchronized
  • Bugzilla 5221: entity.c: Merge Walter's list with Thomas'
  • Bugzilla 5241: dmd: ABI breakage/regression (TypeInfo.toString() returns partially corrupted string)
  • Bugzilla 5242: self referencing template constraint crashes compiler
  • Bugzilla 5244: PATCH: fix use of uninitialised variable in toObj.c
  • Bugzilla 5246: PATCH(s): fix a couple more uninitialised variables
  • Bugzilla 5349: ICE(toir.c): nested class in static member function
  • Bugzilla 5391: Crash with recursive alias declaration
  • Bugzilla 5439: 64bit struct alignment inconsistent with C ABI
  • Bugzilla 5455: ICE(cgcod.c): Optimization (register allocation?) regression in DMD 1.065
  • Bugzilla 5486: Missing define for running dmd as 64 bit
  • Bugzilla 5534: [64-bit] Inexplicable segfault in small code snippet, -O -release -m64 only
  • Bugzilla 5536: Array append with dollar op on 64-bit
  • Bugzilla 5545: [64-bit] DMD fails to postincrement ubytes.
  • Bugzilla 5549: [64-bit] Internal error: backend/cgcod.c 1845
  • Bugzilla 5556: [64-bit] Wrong Implicit Conversion to Double
  • Bugzilla 5557: [64-Bit] FP (alignment?) issues with Rvalues
  • Bugzilla 5564: [64-bit] loading of wrong constant byte value
  • Bugzilla 5565: [64-bit] Wrong Floating Point Results, Related to Mixing With size_t
  • Bugzilla 5566: [64-bit] More erratic FP results with size_t
  • Bugzilla 5571: [64-bit] new bool returns bogus address
  • Bugzilla 5572: [64-bit] Global Hidden Mutexes Seem to share Addresses W/ Global Variables
  • Bugzilla 5580: [64-bit] String switch statements broken in 64-bit mode
  • Bugzilla 5581: [64-bit] Wrong code with bitwise operations on bools
  • Bugzilla 5592: Previous definition different: __arrayExpSliceMulSliceAddass_d
Version D 1.066 Dec 21, 2010

New/Changed Features

Bugs Fixed

  • Bugzilla 603: Undocumented behaviour: case and default create a scope
  • Bugzilla 632: Typedef/enum promotions spec ambiguous - ultimate base type or lowest common denominator?
  • Bugzilla 679: Spec needs allowances for copying garbage collection
  • Bugzilla 690: ABI not fully documented
  • Bugzilla 1351: Discrepancies in the language specification
  • Bugzilla 1466: Spec claims maximal munch technique always works: not for "1..3"
  • Bugzilla 2206: unnamed template mixin of class inside function or class has incorrect classinfo and mangleof
  • Bugzilla 2385: spec says all structs are returned via hidden pointer on linux, but it uses registers
  • Bugzilla 2392: Parsing ambiguity between function pointer declaration and function call
  • Bugzilla 2406: Declarator2 definition error
  • Bugzilla 2556: Property classinfo needs better documentation (RTTI, typeof, typeid, runtime type information)
  • Bugzilla 2616: Undocumented behaviour: part-explicit, part-implicit instantiations of function templates are accepted
  • Bugzilla 2651: class body declaration grammar incorrect
  • Bugzilla 2652: DeclDef grammar is wrong
  • Bugzilla 2734: Ambiguity in tokenizing: _._ as a float literal
  • Bugzilla 2994: Incomplete "Predefined Versions" documentation
  • Bugzilla 3112: Specification on what operations call the GC is missing
  • Bugzilla 3276: Recursion broken by alias template parameter
  • Bugzilla 3554: Ddoc generates invalid output for documentation comments with non paired parantheses
  • Bugzilla 4529: Segfault(typinf.c) involving typeid(typeof(functionName))
  • Bugzilla 4728: Segfault(toctype.c) by protected/private constructor in an other module
  • Bugzilla 4864: ICE(statement.c) Crash on invalid 'if statement' body inside mixin
  • Bugzilla 5110: Excess attribute propagation of structs and classes
  • Bugzilla 5117: [CTFE] Member function call with rather complex this: side effects ignored
  • Bugzilla 5120: ICE(mtype.c) void associative arrays
  • Bugzilla 5145: Regression(2.050, 1.065) override error with forward ref of superclass
  • Bugzilla 5159: Segfault(interpret.c): calling a static function pointer variable in CTFE
  • Bugzilla 5164: Error without line number using "is (T...)"
  • Bugzilla 5180: ICE(arrayop.c) in-place array operation on incompatible types
  • Bugzilla 5182: ICE(expression.c): calling unittest from a function
  • Bugzilla 5195: Forward references ignore const
  • Bugzilla 5230: Regression(2.041, 1.057) ICE(tocsym.c) overriding a method that has an out contract
  • Bugzilla 5238: PATCH: fix return of uninitialised var in interpret.c
  • Bugzilla 5275: x86_64 related hidden function parameter mishandled
  • Bugzilla 5294: -O optimization breaks for loop
  • Bugzilla 5331: mach format problem
Version D 1.065 Oct 29, 2010

New/Changed Features

  • added talign() and argTypes() to TypeInfo
  • Upgrade zlib support to zlib 1.2.5

Bugs Fixed

  • Unlisted bug: signed long comparisons under OS X
  • Bugzilla 3602: ICE(tocsym.c) compiling a class, if its super class has preconditions
  • Bugzilla 3665: Regression(1.051, 2.036) Assignment with array slicing does not work
  • Bugzilla 4398: dmd always uses Windows name mangling for _d_throw may require update to Tango
  • Bugzilla 4623: Non-integer type allowed as static array size
  • Bugzilla 4768: Regression(1.056): wrong code with forward declaration of enum
  • Bugzilla 4825: Regression(1.057, 2.040) "Error: non-constant expression" with -inline
  • Bugzilla 4873: Assertion failure: '0' on line 1483 in file 'expression.c'
  • Bugzilla 4897: CodeView: No locals or parameters are shown when debugging, because of missing function info
  • Bugzilla 4925: [ICE] segfault with module-scope assert(0)
  • Bugzilla 4926: ICE: PREC_zero assertion failure due to unset precedence
  • Bugzilla 4941: Built-in tuple slice boundaries are not CTFE'd
  • Bugzilla 4949: ICE on invalid static if using value of 'this'
  • Bugzilla 5026: ICE(expression.c) Incomplete mixin expression + char[] to char assignment
Version D 1.064 Sep 13, 2010

New/Changed Features

Bugs Fixed

  • Bugzilla 1715: Template specialization checks for equality rather than convertibility
  • Bugzilla 1970: Templated interfaces not matched
  • Bugzilla 2511: Covariant return type doesn't work with circular import
  • Bugzilla 2716: Confusion of auto and scope as the class attribute
  • Bugzilla 3046: Segfault with C++ static variable (Linux only)
  • Bugzilla 3418: link error with cast(ulong)(ulong*real)
  • Bugzilla 3544: optlink termination 0041338f with recursive nested functions
  • Bugzilla 3554: Ddoc generats invalid output for documentation comments with non paired paranthasis
  • Bugzilla 3627: -of with a filename with a double extension confuses linker
  • Bugzilla 4009: OPTLINK ruins the day yet again
  • Bugzilla 4173: Regression(2.037) Explicitly instantiated templates still try to do IFTI in some cases
  • Bugzilla 4278: allow inlining of super calls (undo limitations of bug3500's fix)
  • Bugzilla 4302: Regression(2.046, 1.061): compiler errors using startsWith in CTFE
  • Bugzilla 4645: to!string(const char*) in library causes Optlink to issue warning
  • Bugzilla 4652: Compiler hangs on template with zero-length tuple and another argument
  • Bugzilla 4655: Regression(1.063, 2.048) goto to a try block ICEs
  • Bugzilla 4676: Overload resolution rejects valid code when mixing variadics, non-variadics
  • Bugzilla 4691: Incorrect comparison of double and long
  • Bugzilla 4721: compilation slow when compiling unittests on dcollections
  • Bugzilla 4751: Regression(1.062, 2.047) ICE(constfold.c) >> after error
  • Bugzilla 4752: fail_compilation/fail345.d asserts in expression.c
  • Bugzilla 4771: fail_compilation/fail274.d hits a halt in iasm.c
  • Bugzilla 4828: ICE w/ non-boolean dot expression sth.template_instance in static if
Version D 1.063 Aug 8, 2010

New/Changed Features

  • Bugzilla 4080: Patch for building dynamic libraries on Mac OS X

Bugs Fixed

  • Bugzilla 1418: tupleof bug on nested classes
  • Bugzilla 1678: ref with varargs generates invalid code
  • Bugzilla 2931: Initialization struct with array from another struct
  • Bugzilla 3326: $ in delegate literal causes Access Violation
  • Bugzilla 3560: foreach over nested function generates wrong code
  • Bugzilla 3569: DMD Stack Overflow with a struct member function inside a C-style struct initializer
  • Bugzilla 3679: Regression(2.031) template forward reference regression
  • Bugzilla 3706: delegates of interfaces with multiple inheritance fail
  • Bugzilla 4191: [FreeBSD] real constants are rounded to double precision
  • Bugzilla 4198: [FreeBSD] imprecision in decimal floating-point literals
  • Bugzilla 4238: Segfault(statement.c): with(typeof(int))
  • Bugzilla 4303: __traits(compiles) returns wrong result when used recursively
  • Bugzilla 4314: Regression(1.062): Expression array1 && array2 doesn't compile
  • Bugzilla 4339: Struct destructor + invariant + struct parameter = horrific error message
  • Bugzilla 4396: mkdir race prevents concurrent compiling with DMD using make -j
  • Bugzilla 4443: Optimizer produces wrong code for || or && with struct arrays
  • Bugzilla 4503: forward reference to aliased template instance
  • Bugzilla 4506: Regression(2.034): -O flag breaks some recursive functions
  • Bugzilla 4514: Regression: Cannot cast from X* to X
  • Bugzilla 4569: extern(c++) doesn't understand const types, produces bad mangled symbol
  • Bugzilla 4578: Regression(2.047,1.062): ICE(cgcod.c): var+arr[]
Version D 1.062 Jun 9, 2010

New/Changed Features

  • Bugzilla 2008: Poor optimization of functions with ref parameters
  • Bugzilla 4296: Reduce parasitic error messages

Bugs Fixed

  • Bugzilla 1193: regression: "matches more than one template declaration" doesn't list the location of the conflicting templates
  • Bugzilla 1894: scope(exit) is ignored except in compound statements
  • Bugzilla 1941: missing line on inaccesable external private module member
  • Bugzilla 2127: inliner turns struct "return *this" from by-value into by-ref
  • Bugzilla 2276: Error message missing line number on array operation
  • Bugzilla 2546: Array Ops silently fail when no slice symbol is used.
  • Bugzilla 2881: x.stringof returns typeof(x).stringof when x is an enum
  • Bugzilla 3064: Invalid array operation accepted, generates bad code
  • Bugzilla 3323: Segfault or ICE(e2ir.c) using struct with destructor almost anywhere
  • Bugzilla 3398: Attributes inside a union screws data alignment
  • Bugzilla 3547: for option -od for relative path the path is added twice
  • Bugzilla 3548: ICE occurs when an array is returned from a function is incorrectly used in an array op expression.
  • Bugzilla 3651: mangleof broken for enums
  • Bugzilla 3854: Error on static initialization of arrays with trailing comma.
  • Bugzilla 4003: The result changes only with the order of source files.
  • Bugzilla 4045: [CTFE] increasing array length
  • Bugzilla 4052: [CTFE] increment from array item
  • Bugzilla 4078: [CTFE] Failed return of dynamic array item
  • Bugzilla 4084: Ignored missing main() closing bracket
  • Bugzilla 4143: fix warnings in dmd build
  • Bugzilla 4156: Segfault with array+=array
  • Bugzilla 4169: building dmd with a modern gcc produces a buggy compiler
  • Bugzilla 4175: linux.mak doesn't declare sufficient dependencies to support parallel builds
  • Bugzilla 4210: Random crashes / heisenbugs caused by dmd commit 478: compiler messes up vtables
  • Bugzilla 4212: DWARF: void arrays cause gdb errors
  • Bugzilla 4213: Strange behaviour with static void[] arrays
  • Bugzilla 4242: ICE(module.c): importing a module with same name as package
  • Bugzilla 4252: [CTFE] No array bounds checking in assignment to char[] array
  • Bugzilla 4257: ICE(interpret.c): passing parameter into CTFE as ref parameter
  • Bugzilla 4259: Header generation omits leading '@' for properties
  • Bugzilla 4270: Missing line number in 'can only catch class objects' error message
Version D 1.061 May 10, 2010

New/Changed Features

  • Add hints for missing import declarations.
  • Speed up compilation.

Bugs Fixed

  • Fix hanging problem on undefined identifiers.
  • Bugzilla 461: Constant not understood to be constant when circular module dependency exists.
  • Bugzilla 945: template forward reference with named nested struct only
  • Bugzilla 1055: union forward reference "overlapping initialization" error
  • Bugzilla 2085: CTFE fails if the function is forward referenced
  • Bugzilla 2386: Array of forward referenced struct doesn't compile
  • Bugzilla 4015: forward reference in alias causes error
  • Bugzilla 4016: const initializer cannot forward reference other const initializer
  • Bugzilla 4042: Unable to instantiate a struct template.
  • Bugzilla 4100: Break and continue to label should mention foreach
Version D 1.060 May 4, 2010

New/Changed Features

Bugs Fixed

  • Another try at fixing the Dwarf issues.
Version D 1.059 Apr 30, 2010

New/Changed Features

  • Improve spelling checking distance to 2.

Bugs Fixed

  • Bugzilla 1079: gdb: Dwarf Error: Cannot find DIE at 0xb705 referenced from DIE at 0x250
  • Bugzilla 2549: Segfault on array multiplication.
  • Bugzilla 3066: Array operation without a slice as the lvalue accepted, bad codegen
  • Bugzilla 3207: gdb: Push D patches upstream
  • Bugzilla 3415: broken JSON output
  • Bugzilla 3522: ICE(cg87.c): variable*array[].
  • Bugzilla 3974: ICE(init.c): Static array initializer with more elements than destination array
  • Bugzilla 3987: [gdb] Invalid DWARF output for function pointers
  • Bugzilla 4036: Segfault with -inline and literal of struct containing union
  • Bugzilla 4037: [gdb] Invalid DWARF output for wchar
  • Bugzilla 4038: [gdb] Invalid DWARF output for function pointers with ref args
  • Bugzilla 4067: [CTFE] Code inside try-catch blocks is silently ignored
  • Bugzilla 4089: crash when creating JSON output for incomplete struct
  • Bugzilla 4093: Segfault(interpret.c): with recursive struct templates
  • Bugzilla 4105: Stack overflow involving alias template parameters and undefined identifier
Version D 1.058 Apr 6, 2010

New/Changed Features

Bugs Fixed

  • Bugzilla 122: DDoc newline behaviour produces suboptimal results
  • Bugzilla 1628: Ddoc produces invalid documentation for --- blocks
  • Bugzilla 2609: No documentation generated for destructor
  • Bugzilla 3808: Assertion Failure : Assertion failure: 'classinfo->structsize == CLASSINFO_SIZE' on line 870 in file 'toobj.c'
  • Bugzilla 3842: ICE(expression.c) using pointer in CTFE
  • Bugzilla 3884: Segfault: defining a typedef with an invalid object.d
  • Bugzilla 3885: No multithread support for Windows DLL
  • Bugzilla 3899: CTFE: poor error message for use of uninitialized variable
  • Bugzilla 3900: CTFE: Wrong return value for array.var assignment
  • Bugzilla 3901: PATCH: Nested struct assignment for CTFE
  • Bugzilla 3914: Struct as argument that fits in register has member accessed wrong
  • Bugzilla 3919: ICE(expression.c, 9944): * or / with typedef ireal
  • Bugzilla 3920: Assertion failure: '0' on line 10018 in file 'expression.c'
  • Bugzilla 3958: mixin(non-static method) crashes compiler
  • Bugzilla 3972: Regarding module with name different from its file name
  • Bugzilla 4002: dmd.conf and binary path in dmd -v output
  • Bugzilla 4004: DMD 2.042 CTFE regression with functions taking ref parameters
  • Bugzilla 4005: std.c.stdlib.exit in CTFE and more
  • Bugzilla 4011: Incorrect function overloading using mixins
  • Bugzilla 4019: [CTFE] Adding an item to an empty AA
  • Bugzilla 4020: [ICE][CTFE] struct postblit in CTFE
  • Bugzilla 4027: Closures in CTFE generate wrong code
  • Bugzilla 4029: CTFE: cannot invoke delegate returned from function
Version D 1.057 Mar 7, 2010

New/Changed Features

  • Warnings no longer halt the parsing/semantic passes, though they still return an error status and still do not generate output files. They also no longer count as errors when testing with "compiles" traits.
  • Added -wi switch for Bugzilla 2567
  • Associative array contents can now be compared for equality
  • Add simple spell checking.

Bugs Fixed

  • Bugzilla 2321: spec on inline asm can be misunderstood
  • Bugzilla 2463: No line number in "statement is not reachable" warning
  • Bugzilla 3029: Bug in array value mangling rule
  • Bugzilla 3306: bad function/delegate literal generated into header files
  • Bugzilla 3373: bad codeview debug info for long and ulong
  • Posix only, Bugzilla 3420: [PATCH] Allow string import of files using subdirectories
  • Bugzilla 3450: incorrect result for is (typeof({ ... }())) inside a struct
  • Bugzilla 3500: super behaves differently with -inline
  • Bugzilla 3558: Optimizer bug results in false if condition being taken
  • Bugzilla 3670: Declarator grammar rule is broken
  • Bugzilla 3710: Typo in allMembers description?
  • Bugzilla 3736: corrupted struct returned by function with optimizations (-O)
  • Bugzilla 3737: SEG-V at expression.c:6255 from bad opDispatch
  • Bugzilla 3768: reapeted quotes in ddoc.html
  • Bugzilla 3769: Regression: Segfault(constfold.c) array literals and case statements
  • Bugzilla 3775: Segfault(cast.c): casting no-parameter template function using property syntax
  • Bugzilla 3781: ICE(interpret.c): using no-argument C-style variadic function in CTFE
  • Bugzilla 3792: Regression: "non-constant expression" for a template inside a struct using a struct initializer
  • Bugzilla 3803: compiler segfaults
  • Bugzilla 3840: Jump to: section in the docs should be sorted
Version D 1.056 Jan 29, 2010

New/Changed Features

  • Clarification: function returns are not lvalues
  • Add -map command line switch
  • Delegates and function pointers may be used in CTFE
  • Delegate literals and function literals may be used in CTFE
  • Lazy function parameters may now be used in CTFE
  • Slicing of char[] arrays may now be used in CTFE

Bugs Fixed

  • Bugzilla 48: Internal error: cgreg 784
  • Bugzilla 1298: CTFE: tuple foreach bugs
  • Bugzilla 1790: CTFE: foreach(Tuple) won't compile if Tuple contains string
  • Bugzilla 2101: CTFE: Please may I use mutable arrays at compile time?
  • Partial fix for Bugzilla 3569, stops the stack overflow
  • Bugzilla 3668: foreach over typedef'd array crashes dmd
  • Bugzilla 3674: forward reference error with multiple overloads with same name
  • Bugzilla 3685: Regression(D1 only): DMD silently exits on valid code
  • Bugzilla 3687: Array operation "slice times scalar" tramples over memory
  • Bugzilla 3719: forward references can cause out-of-memory error
  • Bugzilla 3723: Regression: forward referenced enum
  • Bugzilla 3724: bug in Expression::arraySyntaxCopy (null pointer dereference on struct->union->struct)
  • Bugzilla 3726: Regression: ICE(mangle.c 81): struct forward reference with static this
  • Bugzilla 3740: Regression: class with fwd reference of a nested struct breaks abstract
Version D 1.055 Jan 1, 2010

New/Changed Features

Bugs Fixed

  • Bugzilla 3663: struct forward reference regresssion
  • Bugzilla 3664: struct forward declaration causes enum to conflict with itself
Version D 1.054 Dec 30, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 45: Internal error: cgcod 1594
  • Bugzilla 46: Constant folding with long doubles
  • D/103391: D1 garbage collector + threads + malloc = garbage?
  • Bugzilla 282: Bizarre circular import nested name invisibility issue
  • Bugzilla 390: Cannot forward reference enum nested in struct
  • Bugzilla 400: forward reference error; no propety X for type Y (struct within struct)
  • Bugzilla 1160: enums can not be forward referenced
  • Bugzilla 1564: Forward reference error for enum in circular import
  • Bugzilla 2029: Typesafe variadic functions don't work in CTFE
  • Bugzilla 2816: Sudden-death static assert is not very useful
  • Bugzilla 3455: Some Unicode characters not allowed in identifiers
  • Bugzilla 3575: CTFE: member structs not initialized correctly
  • Bugzilla 3584: DeclDef rule is missing entries
  • Bugzilla 3585: Duplicate clauses in EqualExpression and RelExpression rules
  • Bugzilla 3587: Aggregate rule references undefined Tuple
  • Bugzilla 3588: WithStatement rule references unspecified Symbol
  • Bugzilla 3589: BaseClassList and InterfaceClasses rules are incorrect, missing ','
  • Bugzilla 3590: FunctionParameterList rule is missing
  • Bugzilla 3591: TemplateIdentifier rule is misspelled
  • Bugzilla 3592: ClassTemplateDeclaration and FunctionTemplateDeclaration rules are unreferenced
  • Bugzilla 3593: IntegerExpression rule unspecified
  • Bugzilla 3594: AsmPrimaryExp rule references unspecified rules
  • Bugzilla 3595: Several rules are missing ':' after rule name
  • Bugzilla 3601: Debug and Release builds of DMD produce different object files
  • Bugzilla 3611: Enum forward referencing regression
  • Bugzilla 3612: ExpressionList is undefined
  • Bugzilla 3617: CTFE: wrong code for if(x) where x is int or smaller
  • Bugzilla 3628: can't cast null to int
  • Bugzilla 3633: Optimizer causes access violation
  • Bugzilla 3645: manifest constant (enum) crashes dmd
Version D 1.053 Dec 3, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 111: appending a dchar to a char[]
  • Bugzilla 370: Compiler stack overflow on recursive typeof in function declaration.
  • Bugzilla 2229: ICE(template.c) instantiating an invalid variadic template with more than one argument
  • Bugzilla 2967: spec does not mention that inline asm is a valid "return" statement
  • Bugzilla 3115: >>> and >>>= generate wrong code
  • Bugzilla 3171: % not implemented correctly for floats
  • Bugzilla 3381: [tdpl] Incorrect assessment of overriding in triangular-shaped hierarchy
  • Bugzilla 3469: ICE(func.c): Regression. Calling non-template function as a template, from another module
  • Bugzilla 3495: Segfault(typinf.c) instantiating D variadic function with too few arguments
  • Bugzilla 3496: ICE(cgelem.c, optimizer bug) cast(void *)(x&1)== null.
  • Bugzilla 3502: Fix for dropped Mac OS X 10.5
  • Bugzilla 3521: Optimized code access popped register
  • Bugzilla 3540: Another DWARF line number fix
Version D 1.052 Nov 12, 2009

New/Changed Features

  • OSX versions 10.5 and older are no longer supported.

Bugs Fixed

  • Works on OSX 10.6 now.
Version D 1.051 Nov 5, 2009

New/Changed Features

Bugs Fixed

  • Problem with complicated array op expressions
  • Bugzilla 195: DDoc generates bad output when example contains "protected" attribute
  • Bugzilla 424: Unexpected OPTLINK Termination at EIP=0044C37B (too many fixups)
  • Bugzilla 874: Bad codegen: wrong value variable in tuple foreach, D1 only
  • Bugzilla 1117: ddoc generates corrupted docs if code examples contain attributes with colons
  • Bugzilla 1812: DDOC - Unicode identifiers are not correctly marked.
  • Bugzilla 2862: ICE(template.c) using type tuple as function argument
  • Bugzilla 3292: ICE(todt.c) when using a named mixin with an initializer as template alias parameter
  • Bugzilla 3397: Unintended function call to static opCall
  • Bugzilla 3401: Compiler crash on invariant + method overload
  • Bugzilla 3422: ICE(cgcod.c) Structs with default initializers bigger than register size cannot be default parameters
  • Bugzilla 3426: ICE(optimize.c): struct literal with cast, as function default parameter.
  • Bugzilla 3432: ICE(e2ir.c): casting template expression
Version D 1.050 Oct 14, 2009

New/Changed Features

  • Use -X to generate JSON files.

Bugs Fixed

  • Fold in patch from Bugzilla 1170
  • Bugzilla 923: No constant folding for template value default arguments, D1 only
  • Bugzilla 1534: Can't mix in a case statement.
  • Bugzilla 2423: Erroneous unreachable statement warning
  • Bugzilla 3392: a cast of this to void in tango.core.Thread is not allowed
Version D 1.049 Oct 11, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 258: Undefined identifier error for circular import
  • Bugzilla 928: nested struct definition in unittest section of a templated class, hangs DMD
  • Bugzilla 1140: ICE(cod1.c) casting last function parameter to 8 byte value
  • Bugzilla 1592: dmd fail to resolve class symbol when i put files in a package
  • Bugzilla 1787: Compiler segfaults on circular references.
  • Bugzilla 1897: ICE(template.c) with tuple delegate
  • Bugzilla 1934: ICE(e2ir.c) using static array as AA key
  • Bugzilla 2229: ICE(template.c) instantiating an invalid variadic template with more than one argument
  • Bugzilla 2687: ICE(statement.c): tuple foreach in an erroneous template.
  • Bugzilla 2773: ICE(go.c) array assignment through a pointer, only with -O.
  • Bugzilla 2829: ICE(expression.c) static array block-initialized in struct literal
  • Bugzilla 2851: Segfault(expression.c) using C-style struct initializer with too few arguments
  • Bugzilla 3006: ICE(e2ir.c, tocsym.c) template module using array operation
  • Bugzilla 3041: Array slices can be compared to their element type: bad codegen or ICE
  • Bugzilla 3101: Stack overflow: declaring aggregate member twice with static if
  • Bugzilla 3174: ICE(mtype.c): Compiler crash or compiler error with auto returns and const / immutable / invarient / pure
  • Bugzilla 3176: Compiler hangs on poorly formed mixin in variadic template
  • Bugzilla 3261: compiler crash with mixin and forward reference
  • Bugzilla 3286: Default parameter prevents to resolve inter-module circular dependency
  • Bugzilla 3301: Undefined identifier error dependent on order of imports when a circular import is involved
  • Bugzilla 3325: ICE(func.c) function literal with post-contract
  • Bugzilla 3343: Crash by "auto main(){}"
  • Bugzilla 3344: ICE(e2ir.c) returning an invalid function from main()
  • Bugzilla 3357: ICE(cod1.c) using 'in' with a static char array as AA key
  • Bugzilla 3366: Segfault(declaration.c) variadic template with unmatched constraint
  • Bugzilla 3374: [tdpl] ICE(init.c): Associative array type not inferred
Version D 1.048 Oct 5, 2009

New/Changed Features

  • Compiler now detects some cases of illegal null dereferencing when compiled with -O
  • Bugzilla 2905: Faster +-*/ involving a floating-pointing literal

Bugs Fixed

  • gdb stack trace should work now
  • Bugzilla 302: in/out contract inheritance yet to be implemented
  • Bugzilla 718: ICE(cgcod.c) with int /= cast(creal)
  • Bugzilla 814: lazy argument + variadic arguments = segfault
  • Bugzilla 1168: Passing a .stringof of an expression as a template value parameter results in the string of the type
  • Bugzilla 1571: Segfault(class.c) const on function parameters not carried through to .di file
  • Bugzilla 1731: forward reference of function type alias resets calling convention
  • Bugzilla 2202: Error getting type of non-static member of a class
  • Bugzilla 2469: ICE(cod1.c) arbitrary struct accepted as struct initializer
  • Bugzilla 2697: Cast of float function return to ulong or uint gives bogus value
  • Bugzilla 2702: Struct initialisation silently inserts deadly casts
  • Bugzilla 2839: ICE(cgcs.c) with int /= imaginary
  • Bugzilla 3049: ICE(cod4.c) or segfault: Array operation on void[] array
  • Bugzilla 3059: Nonsensical complex op= should be illegal
  • Bugzilla 3160: ICE(cgcod.c 1511-D1) or bad code-D2 returning string from void main
  • Bugzilla 3304: Segfault using 'is' with a pointer enum.
  • Bugzilla 3305: Segfault(expression.c) with recursive struct template alias expressions
  • Bugzilla 3335: minor warning cleanups
  • Bugzilla 3336: ICE(glue.c) declaring AA with tuple key, only with -g
  • Bugzilla 3353: storage class of a member function is propagated to default arguments
Version D 1.047 Sep 2, 2009

New/Changed Features

  • Bugzilla 3122: [patch] Adding support for fast and reliable build tools to the frontend
  • Added support for:
    a[i].var = e2
    and:
    a[] = e
    in CTFE. (thanks, Don!)
  • Member functions can now be used in CTFE
  • Operator overloading can now be used in CTFE
  • Nested functions can now be used in CTFE
  • CTFE error messages now explain why the function could not be interpreted at compile time

Bugs Fixed

  • Fixed bug processing spaces in dmd's directory
  • Bugzilla 601: statement.html - Formatting/markup errors in BNF
  • Bugzilla 1461: Local variable as template alias parameter breaks CTFE
  • Bugzilla 1605: break in switch with goto breaks in ctfe
  • Bugzilla 1948: CTFE fails when mutating a struct in an array
  • Bugzilla 1950: CTFE doesn't work correctly for structs passed by ref
  • Bugzilla 2569: static arrays in CTFE functions don't compile
  • Bugzilla 2575: gdb can not show code
  • Bugzilla 2604: DW_TAG_module and GDB
  • Bugzilla 2940: null is null cannot be evaluated at compile time
  • Bugzilla 2960: CTFE rejects static array to dynamic array casts
  • Bugzilla 3039: -vtls compiler flag not listed in man file
  • Bugzilla 3165: What kind of integer division does D use?
  • Bugzilla 3166: "positive" -> "non-negative" in modulo operator description
  • Bugzilla 3168: Declaring structs as incomplete types no longer works
  • Bugzilla 3170: Forward reference of nested class fails if outer class is not plain
  • Bugzilla 3183: Spec of align attribute needs work
  • Bugzilla 3186: corrections for http://www.digitalmars.com/d/2.0/dmd-osx.html
  • Bugzilla 3192: asm in a anonymous delegate crash the compiler
  • Bugzilla 3196: Segfault(mtype.c) after almost any error involving a delegate literal
  • Bugzilla 3205: CTFE: $ cannot be used in lvalues
  • Bugzilla 3246: ICE(init.c) using indexed array initializer on local array
  • Bugzilla 3264: -O causes wrong "used before set" error when using enum.
Version D 1.046 Jul 6, 2009

New/Changed Features

  • Bugzilla 3080: dmd should output compilation errors to stderr, not stdout

Bugs Fixed

  • Fix dmd crash on multicore Windows.
  • Bugzilla 106: template - mixin sequence
  • Bugzilla 810: Cannot forward reference template
  • Bugzilla 852: ICE(toir.c) using local class in non-static nested function in nested static function
  • Bugzilla 854: TypeTuple in anonymous delegate causes ice in glue.c
  • Bugzilla 1054: regression: circular aliases cause compiler stack overflow
  • Bugzilla 1343: Various errors with static initialization of structs and arrays
  • Bugzilla 1358: ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF
  • Bugzilla 1459: ICE(cgcs.c) on attempt to set value of non-lvalue return struct
  • Bugzilla 1524: ICE(constfold.c) on using "is" with strings in CTFE
  • Bugzilla 1984: Assertion failure: 'e1->type' on line 1198 in file 'constfold.c'
  • Bugzilla 2323: ICE(cgcs.c): taking address of a method of a temporary struct
  • Bugzilla 2429: std.stream.File incorrect flag parsing and sharing mode
  • Bugzilla 2432: complex alias -> mtype.c:125: virtual Type* Type::syntaxCopy(): Assertion `0' failed.
  • Bugzilla 2603: ICE(cgcs.c) on subtracting string literals
  • Bugzilla 2843: ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid
  • Bugzilla 2884: ICE: Assert: 'template.c', line 3773, 'global.errors'
  • Bugzilla 2888: [PATCH] speedup for float * 2.0
  • Bugzilla 2915: [Patch]: Optimize -a*-b into a*b
  • Bugzilla 2923: -O generates bad code for ?:
  • Bugzilla 2932: bad e_ehsize (36 != 52)
  • Bugzilla 2952: Segfault on exit when using array ops with arrays of doubles larger than 8 elements
  • Bugzilla 3003: Need to implicitly add () on member template function calls
  • Bugzilla 3014: ICE(template.c) instantiating template with tuple
  • Bugzilla 3016: Errors in the documentation of std.math.acos
  • Bugzilla 3026: Segfault with incomplete static array initializer
  • Bugzilla 3044: Segfault(template.c) instantiating struct tuple constructor with zero arguments.
  • Bugzilla 3078: NaN reported as equal to zero
  • Bugzilla 3114: optlink failing on multicore machines
  • Bugzilla 3117: dmd crash by *1
  • Bugzilla 3128: Internal error: ..\ztc\cod4.c 2737
  • Bugzilla 3130: Crashed with triple stars
Version D 1.045 May 11, 2009

New/Changed Features

  • Folded in compiler/library changes by Unknown W. Brackets to support Solaris.
  • Migrate Posix uses of std.c.linux.linux to std.c.posix.posix
  • added .typeinfo to ClassInfo Bugzilla 2836: Navigate from ClassInfo to TypeInfo

Bugs Fixed

  • Fix instruction scheduler bug on Linux
  • Bugzilla 642: error: mixin "static this" into where it cannot be
  • Bugzilla 713: circular const definitions with module operator "." cause the compiler to segfault
  • Bugzilla 752: Assertion failure: 'e->type->ty != Ttuple' on line 4518 in file 'mtype.c'
  • Bugzilla 858: Forward reference to struct inside class crashes the compiler
  • Bugzilla 884: Segfault in recursive template
  • Bugzilla 934: Segfault taking mangleof a forward reference in a template.
  • Bugzilla 1011: illegal import declaration causes compile time segfault
  • Bugzilla 1054: regression: circular aliases cause segfaults
  • Bugzilla 1061: "asm inc [;" segfaults compiler.
  • Bugzilla 1195: regression: aliasing an enum member causes compile time segfaults
  • Bugzilla 1305: Compiler hangs with templated opCmp returning templated class
  • Bugzilla 1385: Stack Overflow with huge array literal.
  • Bugzilla 1428: Segfault on template specialization with delegates and tuples
  • Bugzilla 1586: DMD and GDC segfaults on incomplete code segment.
  • Bugzilla 1791: Segmentation fault with anon class in anon class and non-constant variable init
  • Bugzilla 1916: segfault on invalid string concat
  • Bugzilla 1946: Compiler crashes on attempt to implicit cast const typedef to non-const.
  • Bugzilla 2048: DMD crash on CTFE that involves assigning to member variables of void-initialized struct
  • Bugzilla 2061: wrong vtable call with multiple interface inheritance
  • Bugzilla 2215: Forward reference enum with base type within a struct causes Segmentation Fault in the compiler
  • Bugzilla 2309: Crash on a template mixing in a variadic template with an undefined template identifier
  • Bugzilla 2346: ICE when comparing typedef'd class
  • Bugzilla 2821: struct alignment inconsistent with C for { int, long }
  • Bugzilla 2920: recursive templates blow compiler stack
Version D 1.044 Apr 9, 2009

New/Changed Features

  • Added std.c.posix.* to Phobos.

Bugs Fixed

  • Bugzilla 675: %a format has an out-by-1 bug for denormals.
  • Bugzilla 2064: Segfault with mixin(for/foreach) with empty loop body
  • Bugzilla 2199: Segfault using array operation in function call
  • Bugzilla 2203: typeof(class.template.foo) crashes compiler
Version D 1.043 Apr 6, 2009

New/Changed Features

  • Added FreeBSD 7.1 support.

Bugs Fixed

  • Bugzilla 2796: Dependency on libstdc++-v3
Version D 1.042 Mar 31, 2009

New/Changed Features

  • Added response files for Linux and OSX
  • On Windows, if there are multiple source files on the command line they are now read with a background thread. This may speed up compilation.
  • Folded in patches for LDC compatibility from Tomas Lindquist Olsen
  • The Posix version identifier can now be set even though it is reserved and predefined, because many build systems and makefiles try to set it.

Bugs Fixed

  • std.math.hypot is wrong for subnormal arguments
  • Fix bug where / wasn't recognized as a path separator on Windows.
  • Bugzilla 920: Fix one more out of date reference to 'auto' rather than 'scope'
  • Bugzilla 1923: GC optimization for contiguous pointers to the same page
  • Bugzilla 2319: "Win32 Exception" not very useful
  • Bugzilla 2570: Patch for some mistakes in Ddoc comments
  • Bugzilla 2591: custom allocator new argument should be size_t instead of uint
  • Bugzilla 2689: seek behaves incorrectly on MAC OSX
  • Bugzilla 2692: alignment of double on x86 linux is incorrect
  • Bugzilla 2705: Response file size cannot exceed 64kb
  • Bugzilla 2711: -H produces bad headers files if function defintion is templated and have auto return value
  • Bugzilla 2731: Errors in associative array example
  • Bugzilla 2743: dumpobj gives "buss error" on Tiger
  • Bugzilla 2744: wrong init tocbuffer of forstatement
  • Bugzilla 2745: missing token tochars in lexer.c
  • Bugzilla 2747: improper toCBuffer of funcexp
  • Bugzilla 2750: Optimize slice copy with size known at compile time
  • Bugzilla 2751: incorrect scope storage class vardeclaration tocbuffer
  • Bugzilla 2767: DMD incorrectly mangles NTFS stream names
  • Bugzilla 2772: lib can't open response file
Version D 1.041 Mar 3, 2009

New/Changed Features

  • Added buildable dmd source.
  • Improved accuracy of exp, expm1, exp2, sinh, cosh, tanh on Mac OSX, and tripled speed on all platforms.

Bugs Fixed

  • Bugzilla 1629: Link error: Previous Definition Different: blablah__initZ
  • Bugzilla 1662: Falls back to libphobos if -debuglib isn't used when -g is
  • Bugzilla 1681: cast(real) ulong.max == 0
  • Bugzilla 2416: Slice of typedef'ed array should preserve the typedef'ed type
  • Bugzilla 2582: Significantly Increased Compile Times For DWT
  • Bugzilla 2670: std.file.read() should read files of 0 length
  • Bugzilla 2673: Static constructors sometimes do not run when compiling with -lib
  • Bugzilla 2678: for loops are already assumed to terminate
  • Bugzilla 2679: Spurious "warning - " messages and erratic behaviour with is(typeof({void function}()))
  • Bugzilla 2690: DMD aborts with MALLOC_CHECK_ set
Version D 1.040 Feb 11, 2009

New/Changed Features

  • Added Mac OSX support.
  • Separated bin and lib directories into windows, linux, and osx.
  • No longer need to download dmc to use the windows version.
  • Use version(OSX) for Mac OSX. Although version(darwin) is also supported for the time being, it is deprecated.

Bugs Fixed

Version D 1.039 Jan 14, 2009

New/Changed Features

  • Improved speed of long division.
  • Added predefined version D_Ddoc which is predefined when -D switch is thrown.

Bugs Fixed

  • Bugzilla 2517: DDoc omits abstract on classes
  • Bugzilla 2518: scope(success) not execuate and RAII variable destructor is not called
  • Bugzilla 2519: Segfault when >> used in an invalid slice
  • Bugzilla 2527: Alias Template Params Are Always Same Type As First Instantiation (according to typeof(x).stringof)
  • Bugzilla 2531: DDoc not generated correctly for struct methods inside static if
  • Bugzilla 2537: compiler crashes on this code:
  • Bugzilla 2542: array casts behave differently at compile and runtime
Version D 1.038 Dec 11, 2008

New/Changed Features

  • Changed IUnknown to use the extern(System) interface rather that extern(Windows).
  • Added Partial IFTI Bugzilla 493

Bugs Fixed

  • Bugzilla 1518: Crash using 'scope', 'with' and undefined 'RegExp'
  • Bugzilla 1685: Array index is evaluated twice
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2041: Spec implies relationship between interfaces and COM objects
  • Bugzilla 2105: added patch
  • Bugzilla 2468: result type of AndAndExp and OrOrExp deduced incorrectly
  • Bugzilla 2489: import in struct causes assertion failure
  • Bugzilla 2490: extern(C++) can not handle structs as return types
  • Bugzilla 2492: ICE building on Linux with -lib option
  • Bugzilla 2499: Template alias default value cannot be template instantiation
  • Bugzilla 2500: template struct methods are left unresolved if imported from multiple modules
  • Bugzilla 2501: member function marked as final override ignores override requirements
  • Incorporated some of the patches from Bugzilla 1752
Version D 1.037 Nov 25, 2008

New/Changed Features

Bugs Fixed

  • Bugzilla 313: Fully qualified names bypass private imports
  • Bugzilla 341: Undocumented function void print() in object.d
  • Bugzilla 929: Resizing array of associative arrays (uint[char[]][]) causes infinite loop / hang
  • Bugzilla 1372: Compiler accepts pragma(msg,)
  • Bugzilla 1610: Enum.stringof is int, not the name of the enum
  • Bugzilla 1663: pragma(lib, "") don't work on linux
  • Bugzilla 1797: Documentation comments - ///
  • Bugzilla 2326: Methods within final class are not considered final when optimizing
  • Bugzilla 2429: std.stream.File incorrect flag parsing and sharing mode
  • Bugzilla 2431: Internal error: ../ztc/cgcod.c 1031 when using -O
  • Bugzilla 2470: Cannot build libraries from other libraries
  • unittest functions now always use D linkage
Version D 1.036 Oct 20, 2008

New/Changed Features

  • Improved performance of AAs by rebalancing trees when rehashing.

Bugs Fixed

  • Bugzilla 1229: Linker fills disk
  • Bugzilla 2340: Template properties don't work
  • Bugzilla 2365: compilation error: static const array in struct
  • Bugzilla 2368: Calling a function with an address of another function, then calling a returned object is rejected
  • Bugzilla 2373: freebsd select does not accept values > 999,999
  • Bugzilla 2376: CTFE fails on array literal of array literals of chars
  • Bugzilla 2380: static struct initializer accepted as non static initializer is not documented
  • Bugzilla 2383: default arguments can implicitly access private global variables that are not visible at call site
  • Bugzilla 2385: spec says all structs are returned via hidden pointer on linux, but it uses registers
  • Bugzilla 2390: Missing warning on conversion from int to char
Version D 1.035 Sep 2, 2008

New/Changed Features

Bugs Fixed

  • Bugzilla 1627: ICE with a method called _ctor
  • Bugzilla 1633: Nonsensical "C style cast illegal" message with !is
  • Bugzilla 1637: regression: new unittest failure in std/math2.d, odd cosh() behavior
  • Bugzilla 1763: EndianStream doesn't handle ubyte/byte read/writes. Simple fix.
  • Bugzilla 1771: dmd fails to execute on linux
  • Bugzilla 1773: excessively long integer literal
  • Bugzilla 1785: Mixing in an incorrect array literal causes infinite loop.
  • Bugzilla 2176: Assertion failure: 'sz == es2->sz' on line 1339 in file 'constfold.c' (concatenating strings of different types)
  • Bugzilla 2183: Bad formatting in std.c.stdlib
  • Bugzilla 2232: DMD generates invalid code when an object file is compiled -inline
  • Bugzilla 2241: DMD abort
  • Bugzilla 2243: const bool = is(function literal), badly miscast
  • Bugzilla 2262: -inline breaks -lib library
  • Bugzilla 2286: movmskpd compiled incorrectly
  • Bugzilla 2308: CTFE crash on foreach over nonexistent variable
  • Bugzilla 2311: Static destructors in templates are never run
  • Bugzilla 2314: Crash on anonymous class variable instantiation
  • Bugzilla 2317: asm offsetof generates: Internal error: ../ztc/cod3.c 2651
Version D 1.034 Aug 7, 2008

New/Changed Features

  • Now supports array operations.

Bugs Fixed

  • Added hash to generated module names when building libs to reduce collisions
  • Bugzilla 1622: parameters to TypeInfo_Struct.compare seem to be switched around.
  • Bugzilla 2216: bad code generation for static arrays of zero length static arrays
  • Bugzilla 2223: Typo in error message
  • Bugzilla 2242: linux system calls are canceled by GC
  • Bugzilla 2247: bad header file generated for if (auto o = ...) {}
  • Bugzilla 2248: .di should be a supported file extension
  • Bugzilla 2250: Update of user32.lib and kernel32.lib
  • Bugzilla 2254: Size of executable almost triples
  • Bugzilla 2258: Docs -> Inline Assembler -> Operand Types -> qword missing
  • Bugzilla 2259: Assertion failure: '0' on line 122 in file 'statement.c'
  • Bugzilla 2269: D BUG: cosine of complex
  • Bugzilla 2272: synchronized attribute documentation
  • Bugzilla 2273: Whitespace is not inserted after commas
Version D 1.033 Jul 11, 2008

New/Changed Features

Bugs Fixed

  • Bugzilla 870: contradictory error messages for templates
  • Bugzilla 2207: overload resolution fails with deprecation
  • Bugzilla 2208: Deprecated function declarations cannot use deprecated types
  • Bugzilla 2209: Typo in doc for offsetof
Version D 1.032 Jul 9, 2008

New/Changed Features

  • Added .__vptr and .__monitor properties for class objects for use in the internal runtime library.

Bugs Fixed

  • D.announce/12322: mixin regression
  • Bugzilla 203: std.format.doFormat() pads width incorrectly on Unicode strings
  • Bugzilla 211: Linking error with alias mixin params and anonymous methods
  • Bugzilla 224: Incorrect warning "no return at end of function"
  • Bugzilla 252: -w and switch returns = bogus "no return at end of function" warning
  • Bugzilla 253: Invalid <dl> tag generated by Ddoc
  • Bugzilla 294: DDoc: Function templates get double and incomplete documentation
  • Bugzilla 398: No way to abort compilation in a doubly recursive mixin
  • Bugzilla 423: dmd ignores empty commandline arguments
  • Bugzilla 515: Spec incorrect in where .offsetof can be applied
  • Bugzilla 520: Invariants allowed to call public functions
  • Bugzilla 542: Function parameter of a deprecated type (other than a class) is not caught
  • Bugzilla 543: Function return of a deprecated type is not caught
  • Bugzilla 544: Variable declared of a deprecated type (other than a class) is not caught
  • Bugzilla 545: Attempt to access a static built-in property of a deprecated struct, union, enum or typedef is not caught
  • Bugzilla 547: Accessing a deprecated member variable through an explicit object reference is not caught
  • Bugzilla 548: Accessing a value of a deprecated enum is not caught
  • Bugzilla 566: Adding non-static members and functions to classes using a template doesn't error
  • Bugzilla 570: Bogus recursive mixin error
  • Bugzilla 571: class instance member template returns strange value
  • Bugzilla 572: parse error when using template instantiation with typeof
  • Bugzilla 581: Error message w/o line number in dot-instantiated template
  • Bugzilla 617: IFTI doesn't use normal promotion rules for non-template parameters
  • Bugzilla 951: Missing line number: no constructor provided for a class derived from a class with no default constructor
  • Bugzilla 1097: Missing line number: casting array to array of different element size
  • Bugzilla 1158: Missing line number: invalid mixin outside function scope
  • Bugzilla 1176: Error missing file and line number
  • Bugzilla 1187: Segfault with syntax error in two-level mixin.
  • Bugzilla 1194: fcmov* emmits incorrect code
  • Bugzilla 1207: Documentation on destructors is confusing
  • Bugzilla 1341: typeof(int) should probably be legal
  • Bugzilla 1601: shr and shl error message is missing line numbers
  • Bugzilla 1612: No file/line number for using an undefined label in inline assembly
  • Bugzilla 1907: Error message without a line number
  • Bugzilla 1912: Error without line number (Tuple, invalid value argument)
  • Bugzilla 1936: Error with no line number (array dimension overflow)
  • Bugzilla 2161: Modify compiler to pass array TypeInfo to _adEq and _adCmp instead of element TypeInfo
  • Bugzilla 2166: More stuff that doesn't compile in Phobos
  • Bugzilla 2178: 3 errors without line number: typeof
Version D 1.031 June 18, 2008

New/Changed Features

  • Added version identifier D_PIC when -fPIC switch is used.

Bugs Fixed

  • Bugzilla 1383: Implicit Function Instantiation with typesafe-variadic of delegates doesn't work
  • Bugzilla 1559: version statement makes code outside of it disappear
  • Bugzilla 1675: "Identifier too long" error with OMF object files
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2111: Protection incorrectly resolved when accessing super class' tupleof
  • Bugzilla 2118: Inconsistent use of string vs invariant(char[]) in doc
  • Bugzilla 2123: Anonymous class crashes
  • Bugzilla 2132: CTFE: can't evaluate ~= at compile time, D2 only.
  • Bugzilla 2136: typeof(super(...)) counted as a constructor call
  • Bugzilla 2140: static if as final statement with no code causes containing code to be skipped
  • Bugzilla 2143: Mixed-in identifier is not recognized by static if
  • Bugzilla 2144: 'is' is defined to be the same as '==' for non-class and non-array types, but does not call opEquals
  • Bugzilla 2146: Multiple execution of 'static this' defined in template
  • Bugzilla 2149: Auto variables loose the keyword "auto" in di files generated with -H option.
Version D 1.030 May 16, 2008

New/Changed Features

  • Added -lib switch to generate library files.
  • Added -man switch to browse manual.
  • When generating an executable file, only one object file is now generated containing all the modules that were compiled, rather than one object file per module.

Bugs Fixed

  • Bugzilla 2031: Documentation: template value parameters
  • Bugzilla 2032: Documentation for creating a class on the stack is unintuitive
  • Bugzilla 2033: -g + circular refs => dmd hangs
  • Bugzilla 2039: -ignore switch is missing from compiler docs
  • Bugzilla 2044: -g hangs DMD
  • Bugzilla 2055: (ICE) Compiler crash on struct initializer with too many elements
  • Bugzilla 2058: Describe hidden value passed to class member functions
  • Bugzilla 2067: call from anonymous class makes access violation.
  • Bugzilla 2071: spec doesn't mention pointer arithmetic with two pointer operands
  • Bugzilla 2075: Spec does not specify how array literals are stored.
  • Bugzilla 2084: operator ?: does not compute the tightest type
  • Bugzilla 2086: Describe relationship between string and char[] more explicitly
  • Bugzilla 2089: Issues with CTFE and tuple indexes
  • Bugzilla 2090: Cannot alias a tuple member which is a template instance
Version D 1.029 Apr 23, 2008

New/Changed Features

  • Added -ignore switch to ignore unsupported pragmas.
  • Unsupported pragmas now printed out with -v switch.
  • Incorporated Benjamin Shropshire's doc changes

Bugs Fixed

  • Bugzilla 1712: vtbl[0] for interface not set to corresponding Interface*
  • Bugzilla 1741: crash on associative array with static array as index type
  • Bugzilla 1905: foreach docs inconsistency
  • Bugzilla 1906: foreach cannot use index with large arrays
  • Bugzilla 1908: fix closure14.d
  • Bugzilla 1935: The std.recls samples in the DMD .zip are obsolete.
  • Bugzilla 1967: getDirName does not seem to use altsep on windows
  • Bugzilla 1978: Wrong vtable call
  • Bugzilla 1991: Dmd hangs
  • Bugzilla 2019: Appending a one-element array literal doesn't work
Version D 1.028 Mar 6, 2008

New/Changed Features

  • Added compile time error for comparing class types against null.

Bugs Fixed

  • Fixed dwarf bug with DT_AT_upper_bound
  • Bugzilla 756: IFTI for tuples only works if tuple parameter is last
  • Bugzilla 1454: IFTI cant deduce parameter if alias argument used
  • Bugzilla 1661: Not possible to specialize on template with integer parameter
  • Bugzilla 1809: template.c:2600
  • Bugzilla 1810: MmFile anonymous mapping does not work under win32
  • Bugzilla 1819: spurious warning about missing return statement after synchronized
  • Bugzilla 1828: Several Thread Issues
  • Bugzilla 1833: std.c.windows.windows should use enums for constants, or be more selective about use of extern(Windows)
  • Bugzilla 1836: Inline assembler can't use enum values as parameters.
  • Bugzilla 1837: Make dmd stop flooding the console: prints content of passed parameter file
  • Bugzilla 1843: Bogus unreachable statement on forward referenced struct, lacks line number
  • Bugzilla 1850: The compiler accepts lower case asm registers.
  • Bugzilla 1852: you get opCall missing when cast to a struct(diagnostic)
  • Bugzilla 1853: opCmp documentation really needs some examples
  • Bugzilla 1857: Runtime segfault while profileing - jump to invalid code address
  • Bugzilla 1862: asm: [ESI+1*EAX] should be a legal addr mode
  • Bugzilla 1864: Variable incorrectly declared final in final class template
  • Bugzilla 1865: Escape sequences are flawed.
  • Bugzilla 1877: Errors in the documentation of std.math.atan2
  • Bugzilla 1879: Compiler segfaults on 'scope' and 'static if'
  • Bugzilla 1882: Internal error: ..\ztc\cod1.c 2529
Version D 1.027 Feb 18, 2008

New/Changed Features

  • Re-enabled auto interfaces.

Bugs Fixed

  • Fixed display of ddoc template parameters that were aliased
  • Bugzilla 1072: CTFE: crash on for loop with blank increment
  • Bugzilla 1435: DDoc: Don't apply DDOC_PSYMBOL everywhere
  • Bugzilla 1825: local instantiation and function nesting
  • Bugzilla 1837: Make dmd stop flooding the console: prints content of passed parameter file
  • Bugzilla 1842: Useless linker command line output during compilation on Linux
Version D 1.026 Jan 20, 2008

New/Changed Features

  • WinMain and DllMain can now be in template mixins.

Bugs Fixed

  • Bugzilla 1697: Internal error: ..\ztc\cgcod.c 2322 with -O
  • Bugzilla 1707: '==' in TemplateParameterList in IsExpression causes segfault
  • Bugzilla 1711: typeof with delegate literal not allowed as template parameter
  • Bugzilla 1718: obscure exit with error code 5
  • Bugzilla 1719: Compiler crash or unstable code generation with scoped interface instances
  • Bugzilla 1724: Internal error: toir.c 177
  • Bugzilla 1725: std.stream.BufferedFile.create should use FileMode.OutNew
  • Bugzilla 1767: rejects-valid, diagnostic
  • Bugzilla 1769: Typo on the page about exceptions
  • Bugzilla 1773: excessively long integer literal
  • Bugzilla 1779: Compiler crash when deducing more than 2 type args
  • Bugzilla 1783: DMD 1.025 asserts on code with struct, template, and alias
  • Bugzilla 1788: dmd segfaults without info
Version D 1.025 Jan 1, 2008

Bugs Fixed

  • Bugzilla 1111: enum value referred to by another value of same enum is considered as enum's base type, not enum type
  • Bugzilla 1720: std.math.NotImplemented missing a space in message
  • Bugzilla 1738: Error on struct without line number
  • Bugzilla 1742: CTFE fails on some template functions
  • Bugzilla 1743: interpret.c:1421 assertion failure on CTFE code
  • Bugzilla 1744: CTFE: crash on assigning void-returning function to variable
  • Bugzilla 1749: std.socket not thread-safe due to strerror
  • Bugzilla 1753: String corruption in recursive CTFE functions
Version D 1.024 Nov 27, 2007

New/Changed Features

  • Changed the way coverage analysis is done so it is independent of order dependencies among modules.

Bugs Fixed

  • Bugzilla 70: valgrind: Conditional jump or move depends on uninitialised value(s) in elf_findstr
  • Bugzilla 71: valgrind: Invalid read of size 4 in elf_renumbersyms
  • Bugzilla 204: Error message on attempting to instantiate an abstract class needs to be improved
  • Bugzilla 1508: dmd/linux template symbol issues
  • Bugzilla 1656: illegal declaration accepted
  • Bugzilla 1664: (1.23).stringof generates bad code
  • Bugzilla 1665: Internal error: ..\ztc\cod2.c 411
Version D 1.023 Oct 31, 2007

New/Changed Features

  • Data items in static data segment >= 16 bytes in size are now paragraph aligned.

Bugs Fixed

  • Bugzilla 318: wait does not release thread resources on Linux
  • Bugzilla 322: Spawning threads which allocate and free memory leads to pause error on collect
  • Bugzilla 645: Race condition in std.thread.Thread.pauseAll
  • Bugzilla 689: Clean up the spec printfs!
  • Bugzilla 697: No const folding on asm db,dw, etc
  • Bugzilla 706: incorrect type deduction for array literals in functions
  • Bugzilla 708: inline assembler: "CVTPS2PI mm, xmm/m128" fails to compile
  • Bugzilla 709: inline assembler: "CVTPD2PI mm, xmm/m128" fails to compile
  • Bugzilla 718: Internal error: ../ztc/cgcod.c 562
  • Bugzilla 723: bad mixin of class definitions at function level: func.c:535: virtual void FuncDeclaration::semantic3(Scope*): Assertion `0' failed
  • Bugzilla 725: expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed.
  • Bugzilla 726: incorrect error line for "override" mixin
  • Bugzilla 729: scope(...) statement in SwitchBody causes compiler to segfault
  • Bugzilla 733: std.conv.toFloat does not catch errors
  • Bugzilla 1258: Garbage collector loses memory upon array concatenation
  • Bugzilla 1478: Avoid libc network api threadsafety issues
  • Bugzilla 1480: std.stream throws the new override warning all over the place
  • Bugzilla 1483: Errors in threads not directed to stderr
  • Bugzilla 1491: Suppress SIGPIPE when sending to a dead socket
  • Bugzilla 1557: std.zlib allocates void[]s instead of ubyte[]s, causing leaks.
  • Bugzilla 1562: Deduction of template alias parameter fails
  • Bugzilla 1575: Cannot do assignment of tuples
  • Bugzilla 1593: ICE compiler crash empty return statement in function
  • Bugzilla 1613: DMD hangs on syntax error
  • Bugzilla 1618: Typo in std\system.d
Version D 1.022 Oct 1, 2007

Bugs Fixed

  • Fix std.boxer boxing of Object's (unit test failure)
  • Fix std.demangle to not show hidden parameters (this and delegate context pointers)
  • Bugzilla 217: typeof not working properly in internal/object.d
  • Bugzilla 218: Clean up old code for packed bit array support
  • Bugzilla 223: Error message for unset constants doesn't specify error location
  • Bugzilla 278: dmd.conf search path doesn't work
  • Bugzilla 479: can't compare arrayliteral statically with string
  • Bugzilla 549: A class derived from a deprecated class is not caught
  • Bugzilla 550: Shifting by more bits than size of quantity is allowed
  • Bugzilla 551: Modulo operator works with imaginary and complex operands
  • Bugzilla 556: is (Type Identifier : TypeSpecialization) doesn't work as it should
  • Bugzilla 668: Use of *.di files breaks the order of static module construction
  • Bugzilla 1125: Segfault using tuple in asm code, when size not specified
  • Bugzilla 1437: dmd crash: "Internal error: ..\ztc\cod4.c 357"
  • Bugzilla 1474: regression: const struct with an initializer not recognized as a valid alias template param
  • Bugzilla 1484: Forward reference of enum member crashes DMD
  • Bugzilla 1488: Bad code generation when using tuple from asm
  • Bugzilla 1510: ICE: Assertion failure: 'ad' on line 925 in file 'func.c'
  • Bugzilla 1523: struct literals not work with typedef
  • Bugzilla 1531: cannot access typedef'd class field
  • Bugzilla 1537: Internal error: ..\ztc\cgcod.c 1521
  • Bugzilla 1609: TypeInfo_Typedef has incorrect implementation of next()
Version D 1.021 Sep 5, 2007

New/Changed Features

  • Added command line switches -defaultlib and -debuglib
  • Bugzilla 1445: Add default library options to sc.ini / dmd.conf
  • Added trace_term() to object.d to fix Bugzilla 971: No profiling output is generated if the application terminates with exit
  • Multiple module static constructors/destructors allowed.

Bugs Fixed

  • Bugzilla 961: std.windows.registry stack corruption
  • Bugzilla 1315: CTFE doesn't default initialise arrays of structs
  • Bugzilla 1363: Compile-time issue with structs in 'for'
  • Bugzilla 1375: CTFE fails for null arrays
  • Bugzilla 1378: A function call in an array literal causes compiler to crash
  • Bugzilla 1384: Compiler segfaults when using struct variable like a function with no opCall member.
  • Bugzilla 1388: multiple static constructors allowed in module
  • Bugzilla 1414: compiler crashes with CTFE and structs
  • Bugzilla 1423: Registry: corrupted value
  • Bugzilla 1436: std.date.getLocalTZA() returns wrong values when in DST under Windows
  • Bugzilla 1447: CTFE does not work for static member functions of a class
  • Bugzilla 1448: UTF-8 output to console is seriously broken
  • Bugzilla 1450: Registry: invalid UTF-8 sequence
  • Bugzilla 1460: Compiler crash on valid code
  • Bugzilla 1464: "static" foreach breaks CTFE
Version D 1.020 Jul 23, 2007

Bugs Fixed

  • Fixed extern (System)
Version D 1.019 Jul 21, 2007

New/Changed Features

  • Added 0x78 Codeview extension for type dchar.
  • Added extern (System)
  • Bugzilla 345: updated std.uni.isUniAlpha to Unicode 5.0.0

Bugs Fixed

  • Bugzilla 46: Included man files should be updated
  • Bugzilla 268: Bug with SocketSet and classes
  • Bugzilla 406: std.loader is broken on linux
  • Bugzilla 561: Incorrect duplicate error message when trying to create instance of interface
  • Bugzilla 588: lazy argument and nested symbol support to std.demangle
  • Bugzilla 668: Use of *.di files breaks the order of static module construction
  • Bugzilla 1110: std.format.doFormat + struct without toString() == crash
  • Bugzilla 1199: Strange error messages when indexing empty arrays or strings at compile time
  • Bugzilla 1300: Issues with struct in compile-time function
  • Bugzilla 1306: extern (Windows) should work like extern (C) for variables
  • Bugzilla 1331: header file genaration generates a ":" instead of ";" at pragma
  • Bugzilla 1332: Internal error: ../ztc/cod4.c 357
  • Bugzilla 1333: -inline ICE: passing an array element to an inner class's constructor in a nested function, all in a class or struct
  • Bugzilla 1336: Internal error when trying to construct a class declared within a unittest from a templated class.
Version D 1.018 Jul 1, 2007

Bugs Fixed

  • Bugzilla 540: Nested template member function error - "function expected before ()"
  • Bugzilla 559: Final has no effect on methods
  • Bugzilla 627: Concatenation of strings to string arrays with ~ corrupts data
  • Bugzilla 629: Misleading error message "Can only append to dynamic arrays"
  • Bugzilla 639: Escaped tuple parameter ICEs dmd
  • Bugzilla 641: Complex string operations in template argument ICEs dmd
  • Bugzilla 657: version(): ignored
  • Bugzilla 689: Clean up the spec printfs!
  • Bugzilla 1103: metastrings.ToString fails for long > 0xFFFF_FFFF
  • Bugzilla 1107: CodeView: wrong CV type for bool
  • Bugzilla 1118: weird switch statement behaviour
  • Bugzilla 1186: Bind needs a small fix
  • Bugzilla 1199: Strange error messages when indexing empty arrays or strings at compile time
  • Bugzilla 1200: DMD crash: some statements containing only a ConditionalStatement with a false condition
  • Bugzilla 1203: Cannot create Anonclass in loop
  • Bugzilla 1204: segfault using struct in CTFE
  • Bugzilla 1206: Compiler hangs on this() after method in class that forward references struct
  • Bugzilla 1207: Documentation on destructors is confusing
  • Bugzilla 1211: mixin("__LINE__") gives incorrect value
  • Bugzilla 1212: dmd generates bad line info
  • Bugzilla 1216: Concatenation gives 'non-constant expression' outside CTFE
  • Bugzilla 1217: Dollar ($) seen as non-constant expression in non-char[] array
  • Bugzilla 1219: long.max.stringof gets corrupted
  • Bugzilla 1224: Compilation does not stop on asserts during CTFE
  • Bugzilla 1228: Class invariants should not be called before the object is fully constructed
  • Bugzilla 1233: std.string.ifind(char[] s, char[] sub) fails on certain non ascii strings
  • Bugzilla 1234: Occurrence is misspelled almost everywhere
  • Bugzilla 1235: std.string.tolower() fails on certain utf8 characters
  • Bugzilla 1236: Grammar for Floating Literals is incomplete
  • Bugzilla 1239: ICE when empty tuple is passed to variadic template function
  • Bugzilla 1242: DMD AV
  • Bugzilla 1244: Type of array length is unspecified
  • Bugzilla 1247: No time zone info for India
  • Bugzilla 1285: Exception typedefs not distinguished by catch
  • Bugzilla 1287: Iterating over an array of tuples causes "glue.c:710: virtual unsigned int Type::totym(): Assertion `0' failed."
  • Bugzilla 1290: Two ICEs, both involving real, imaginary, ? : and +=.
  • Bugzilla 1291: .stringof for a class type returned from a template doesn't work
  • Bugzilla 1292: Template argument deduction doesn't work
  • Bugzilla 1294: referencing fields in static arrays of structs passed as arguments generates invalid code
  • Bugzilla 1295: Some minor errors in the lexer grammar
Version D 1.017 Jun 25, 2007

New/Changed Features

  • Added __VENDOR__ and __VERSION__.
  • The .init property for a variable is now based on its type, not its initializer.

Bugs Fixed

  • std.compiler now is automatically updated.
  • Fixed CFTE bug with e++ and e--.
  • Bugzilla 1254: Using a parameter initialized to void in a compile-time evaluated function doesn't work
  • Bugzilla 1256: "with" statement with symbol
  • Bugzilla 1259: Inline build triggers an illegal error msg "Error: S() is not an lvalue"
  • Bugzilla 1260: Another tuple bug
  • Bugzilla 1261: Regression from overzealous error message
  • Bugzilla 1262: Local variable of struct type initialized by literal resets when compared to .init
  • Bugzilla 1263: Template function overload fails when overloading on both template and non-template class
  • Bugzilla 1268: Struct literals try to initialize static arrays of non-static structs incorrectly
  • Bugzilla 1269: Compiler crash on assigning to an element of a void-initialized array in CTFE
  • Bugzilla 1270: -inline produces an ICE
  • Bugzilla 1272: problems with the new 1.0 section
  • Bugzilla 1276: static assert message displayed with escaped characters
  • Bugzilla 1283: writefln: formatter applies to following variable
Version D 1.016 Jun 14, 2007

New/Changed Features

  • The compiler was not changed.
  • Added aliases string, wstring, and dstring to ease compatiblity with 2.0.

Bugs Fixed

    Version D 1.015 Jun 5, 2007

    Bugs Fixed

    • Added missing \n to exception message going to stderr.
    • Fixed default struct initialization for CTFE.
    • Bugzilla 1226: ICE on a struct literal
    • Fixed gc memory corrupting problem.
    Version D 1.014 Apr 26, 2007

    New/Changed Features

    • Added associative array literals
    • Added struct literals
    • Array element assignments can now be done in CTFE

    Bugs Fixed

    • Bugzilla 1000: writefln fails on nested arrays
    • Bugzilla 1143: Assertion failure: '0' on line 850 in 'template.c' - On specialization of IFTI template parameters.
    • Bugzilla 1144: template mixin causes DMD crash
    • Bugzilla 1146: mixin + assert() crashes compiler
    • Bugzilla 1153: dmd assertion failure
    • Bugzilla 1159: Various mixins cause "CompileExp::semantic" message, some crash DMD
    • Bugzilla 1174: Program hangs creating an array of enums with nonzero initializer
    • Bugzilla 1177: $ no longer works inside CTFE functions.
    • Bugzilla 1180: the GC failes to handle large allocation requests propperly
    • Bugzilla 1189: Reverse the titles on web pages
    Version D 1.013 Apr 19, 2007

    Bugs Fixed

    • Fixed crash with std.format and static arrrays
    • Bugzilla 582: Cannot slice mixed tuples
    • Bugzilla 594: can't cast arrayliteral statically
    • Bugzilla 595: can't append to array/arrayliteral statically
    • Bugzilla 997: [Regression] Struct-returning function that conditionally passes the result of another function straight through doesn't work (NRVO bug?)
    • Bugzilla 1090: Attribute specification: "}" vs "end of scope"
    • Bugzilla 1091: Wrong size reserved for critical sections
    • Bugzilla 1094: switch bug
    • Bugzilla 1096: Mysterious hang with toUTCString + UTCtoLocalTime + d_time_nan
    • Bugzilla 1098: symbol collision in d/dmd/expression.c between math.h and port.h
    • Bugzilla 1119: Internal error: ../ztc/cgcod.c 2190 (template instantiation)
    • Bugzilla 1121: Assertion codegen issue with templated function
    • Bugzilla 1132: DMD calling linker over commandline
    • Bugzilla 1134: incorrect calling convention used
    • Bugzilla 1135: invariant keyword parsing is messed up
    • Bugzilla 1147: Typo in phobos/std/file.d: 4069 should be 4096
    • Bugzilla 1148: Problems returning structs from functions
    • Bugzilla 1150: Compiler creates wrong code
    • Bugzilla 1156: Installed libraries need to be passed in different order
    • Bugzilla 1163: Can't initialize multiple variables with void.
    Version D 1.012 Apr 12, 2007

    Bugs Fixed

    • D.announce/8190 now works with -v1
    • D.announce/8193
    • Bugzilla 532: Wrong name mangling for template alias params of local vars
    • Bugzilla 1068: stack corruption with mixins and function templates
    • Bugzilla 1089: Unsafe pointer comparison in TypeInfo_Pointer.compare
    • Bugzilla 1127: -v1 doesn't disable the ref and macro keywords
    Version D 1.011 Apr 11, 2007

    New/Changed Features

    • Extended Codeview symbolic debug output with LF_OEM types.
    • Extended Dwarf symbolic debug output with DW_TAG_darray_type, DW_TAG_aarray_type, and DW_TAG_delegate types.
    • Added keywords ref and macro.
    • final classes cannot be subclassed.
    • final for variables now works.
    • ref now works as a replacement for inout.
    • Fixed so multiple type inferring declarations like auto a=1,c=2; works.

    Bugs Fixed

    • Fixed problem with overloading of function templates that have the same template parameter list, but different function parameters.
    • Fixed problems with type deduction from specializations that are template instances.
    • Fixed assert template.c(2956) s->parent
    • Got .property to work for typeof.
    • Fixed bug in DW_AT_comp_dir output for some linux versions.
    • D.announce/8027
    • D.announce/8047
    • D/51800
    • Bugzilla 1028: Segfault using tuple inside asm code.
    • Bugzilla 1052: DMD 1.009 - aliasing functions from superclasses may result in incorrect conflicts
    • Bugzilla 1080: Failed to link to std.windows.registry
    • Bugzilla 1081: with using real and -O option, dmd generate bug code
    • Bugzilla 1082: The .offsetof property yields a signed int, a size_t would be more appropriate
    • Bugzilla 1086: CodeView: missing line information for string switch
    • Bugzilla 1092: compiler crash in ..\ztc\cod1.c 2528
    • Bugzilla 1102: switch case couldn't contain template member
    • Bugzilla 1108: Indexing an int[] not evaluatable at compile time
    • Bugzilla 1122: dmd generate bad line number while reporting error message
    Version D 1.010 Mar 24, 2007

    New/Changed Features

    • Added template partial specialization derived from multiple parameters.
    • Added Object.factory(char[] classname) method to create class objects based on a string.
    • Added std.gc.malloc(), std.gc.extend() and std.gc.capacity().
    • Added std.string.isEmail() and std.string.isURL().
    • Added std.stdio.readln().
    • Improved gc performance for array resize and append.
    • Bugzilla 64: Unhandled errors should go to stderr
    • Added predefined Ddoc macro DOCFILENAME

    Bugs Fixed

    • Fixed Broken link in http://digitalmars.com/d/comparison.html
    • Fixed problem with CTFE and array literals
    • Bugzilla 931: D Strings vs C++ Strings Page Incorrect
    • Bugzilla 935: Extern Global C Variables
    • Bugzilla 948: operatoroverloading.html - Rationale section is both out of date and incomplete
    • Bugzilla 950: Missing filename and line number: conflict between implicit length in [...] and explicit length declared in the scope
    • Bugzilla 959: smaller ddoc documentation issue
    • Bugzilla 1056: segfault with pragma(msg) inside CTFE
    • Bugzilla 1062: Cannot catch typedef'd class
    • Bugzilla 1074: Dead link to std.c.locale webpage
    Version D 1.009 Mar 10, 2007

    Bugs Fixed

    • D/49928 1
    • D.announce 7563
    • Bugzilla 146: Wrong filename in DWARF debugging information for templates
    • Bugzilla 992: CTFE Failure with static if
    • Bugzilla 993: incorrect ABI documentation for float parameters
    • Bugzilla 995: compile-time function return element of Tuple / const array
    • Bugzilla 1005: dmd: tocsym.c:343: virtual Symbol* FuncDeclaration::toSymbol(): Assertion `0' failed.
    • Bugzilla 1009: CodeView: out and inout parameters are declared void*
    • Bugzilla 1014: Error with character literal escaping when generating header with -H
    • Bugzilla 1016: CTFE fails with recursive functions
    • Bugzilla 1017: CTFE doesn't support (string == string)
    • Bugzilla 1018: regression: Error: divide by 0
    • Bugzilla 1019: regression: missing filename and line number: Error: array index X is out of bounds [0 .. Y]
    • Bugzilla 1020: regression: mov EAX, func
    • Bugzilla 1021: CTFE and functions returning void
    • Bugzilla 1022: CodeView: unions have zero length in typeleafs and datasymbols
    • Bugzilla 1026: dmd SEGV when checking length of Tuple elements when length == 0
    • Bugzilla 1030: ICE one-liner; struct in delegate
    • Bugzilla 1038: explicit class cast breakage in 1.007
    Version D 1.007 Feb 20, 2007

    New/Changed Features

    • Comparison operators are no longer associative; comparison, equality, identity and in operators all have the same precedence.
    • out and inout parameters are now allowed for compile time function execution.
    • The .dup property is now allowed for compile time function execution.
    • Updated lib to insert COMDATs into symbol table.
    • Class references can no longer be implicitly converted to void*.

    Bugs Fixed

    • D/48806 crash
    • D/48811
    • D/48845
    • D/48869
    • D/48917
    • D/48953
    • D/48990
    • D/49033
    • D.announce/7496
    • Bugzilla 968: ICE on compile-time execution
    • Bugzilla 974: compile-time parenthesis bug
    • Bugzilla 975: compile-time const array makes dmd crash
    • Bugzilla 980: If a function tries to concatenate a char to a empty array, dmd complains that the function can't be evaluated at compile time
    • Bugzilla 981: CFTE fails in non-template and functions that takes no args.
    • Bugzilla 986: Internal error: e2ir.c 1098
    Version D 1.006 Feb 15, 2007

    New/Changed Features

    • Added -J path switch, which is now required in order to import text files.
    • Enhanced -v output to include actual filename.
    • name string for TypeInfo_Struct now part of the TypeInfo_Struct comdat.
    • Compile time execution of functions

    Bugs Fixed

    • Bugzilla 960: New: DMD 1.0 is in the past -- not the future
    • Codeview for classes now gives correct LF_CLASS
    Version D 1.005 Feb 5, 2007

    New/Changed Features

    • -v now emits pragma library statements and imported file names
    • deprecated ===, and !==, tokens no longer recognized
    • length can no longer shadow other length declarations
    • Added MixinStatements, MixinExpressions, and MixinDeclarations.
    • Added ImportExpressions.
    • Added std.metastrings

    Bugs Fixed

    • Bugzilla 761: std.format.doFormat fails for items of a char[][] containing %s
    • Bugzilla 784: regression: [Issue 402] compiler crash with mixin and forward reference
    • Bugzilla 787: incorrect documentation of std.ctype.isprint
    • Bugzilla 788: Compiler rejects hex floats in the format: HexPrefix HexDigits . HexDigits(opt) with binary-exponent-part required
    • Bugzilla 789: const initialization in forwarding constructors doesn't work
    • Bugzilla 791: dhry.d example doesn't compile in 1.0 without trivial change
    • Bugzilla 794: std.math.exp2(0) equals 0 instead of 1
    • Bugzilla 800: writefln() on an associative array fails hard
    • Bugzilla 821: segfault with char array copy; mistaken samples in doc
    • Bugzilla 831: Warning!! String literals are read-only one some platforms.
    • Bugzilla 832: NRVO: return inside foreach results in junk
    • Bugzilla 835: RegExp.test wrongly matches strings on case insensitive attribute
    • Bugzilla 846: Error 42: Symbol Undefined _D1a7__arrayZ
    • Bugzilla 848: typo in C sorting example
    • Bugzilla 862: Selectively importing a nonexistent identifier results in spurious and incorrect error message
    • Bugzilla 872: Assertion in expression.c caused by taking typeof of "this.outer" in nested classes.
    • Bugzilla 875: crash in glue.c line 700
    • Bugzilla 886: std.zlib uncompression routines do not mark result as containing no pointers
    • Bugzilla 887: TypeInfo does not correctly override opCmp, toHash
    • Bugzilla 888: -cov and _ModuleInfo linking bugs
    • Bugzilla 890: Returning char[4] and assigning to char[] produces unexpected results.
    • Bugzilla 891: Crash when compiling the following code (tested with 1.0, 1.001 and 1.002)
    • Bugzilla 893: The profile flag no longer seems to work on Linux x86 64
    • Bugzilla 894: base class with implemented abstract method problem
    • Bugzilla 897: fix default dmd.conf file
    • Bugzilla 898: std.conv.toInt doesn't raise ConvOverflowError
    • Bugzilla 901: Comparison of array literals fails
    • Bugzilla 903: Example with printf and string literals crashes
    • Bugzilla 908: compiler dies trying to inline static method call to nonstatic method in template code.
    • Bugzilla 910: Error in description of "this" and "super" keywords
    • Bugzilla 913: deprecated tokens still listed
    • Bugzilla 915: dmd generate bad form return(retn 4) for invariant func
    • Bugzilla 916: regression: Internal error: ../ztc/gloop.c 1305
    • Bugzilla 917: regression: circular typedefs cause segfaults
    • Bugzilla 924: GC collects valid objects
    • D.announce/6983
    Version D 1.004 Jan 26, 2007

    Bugs Fixed

    • Bugzilla 892: Another bug in the new GC - pointers in mixins
    Version D 1.003 Jan 26, 2007

    Bugs Fixed

    • D.announce/6929
    • D.announce/6953
    Version D 1.002 Jan 24, 2007

    Bugs Fixed

    • D.announce/6893: ClassInfo.flags incorrectly set
    • D.announce/6906: Three subtle cases of tail recursion item 1 and 2
    Version D 1.001 Jan 23, 2007

    New/Changed Features

    • tail recursion works again
    • New type aware GC

    Bugs Fixed

    • Bugzilla 621: When inside a loop, if you call break inside a try block the finally block is never executed
    • Bugzilla 804: missing linux functions
    • Bugzilla 815: scope(exit) isn't executed when "continue" is used to continue a while-loop
    • Bugzilla 817: const char[] = string_literal - string_literal gets included for every reference
    • Bugzilla 819: mention response files in cmd line usage
    • Bugzilla 820: gc should scan only pointer types for pointers
    • Bugzilla 823: frontend: incorrect verror declaration in mars.h
    • Bugzilla 824: "mov EAX, func;" and "lea EAX, func;" generate incorrect code
    • Bugzilla 825: dmd segmentation fault with large char[] template value parameter
    • Bugzilla 826: ICE: is-expression with invalid template instantiation

    Forums | Comments | D | Search | Downloads | Home
    Copyright © 1999-2013 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc.


Rationale

Last update Sun Dec 30 20:34:43 2012

Rationale

Questions about the reasons for various design decisions for D often come up. This addresses many of them.

Operator Overloading

Why not name them operator+(), operator*(), etc.?

This is the way C++ does it, and it is appealing to be able to refer to overloading '+' with 'operator+'. The trouble is things don't quite fit. For example, there are the comparison operators <, <=, >, and >=. In C++, all four must be overloaded to get complete coverage. In D, only a cmp() function must be defined, and the comparison operations are derived from that by semantic analysis.

Overloading operator/() also provides no symmetric way, as a member function, to overload the reverse operation. For example,

class A
{
    int operator/(int i);		// overloads (a/i)
    static operator/(int i, A a)	// overloads (i/a)
}

The second overload does the reverse overload, but it cannot be virtual, and so has a confusing asymmetry with the first overload.

Why not allow globally defined operator overload functions?

  1. Operator overloading can only be done with an argument as an object, so they logically belong as member functions of that object. That does leave the case of what to do when the operands are objects of different types:
    class A { }
class B { }
int opAdd(class A, class B);
    Should opAdd() be in class A or B? The obvious stylistic solution would be to put it in the class of the first operand,
    class A
{
    int opAdd(class B) { }
}
  2. Operator overloads usually need access to private members of a class, and making them global breaks the object oriented encapsulation of a class.
  3. (2) can be addressed by operator overloads automatically gaining "friend" access, but such unusual behavior is at odds with D being simple.

Why not allow user definable operators?

These can be very useful for attaching new infix operations to various unicode symbols. The trouble is that in D, the tokens are supposed to be completely independent of the semantic analysis. User definable operators would break that.

Why not allow user definable operator precedence?

The trouble is this affects the syntax analysis, and the syntax analysis is supposed to be completely independent of the semantic analysis in D.

Why not use operator names like __add__ and __div__ instead of opAdd, opDiv, etc.?

__ keywords should indicate a proprietary language extension, not a basic part of the language.

Why not have binary operator overloads be static members, so both arguments are specified, and there no longer is any issue with the reverse operations?

This means that the operator overload cannot be virtual, and so likely would be implemented as a shell around another virtual function to do the real work. This will wind up looking like an ugly hack. Secondly, the opCmp() function is already an operator overload in Object, it needs to be virtual for several reasons, and making it asymmetric with the way other operator overloads are done is unnecessary confusion.

Properties

Why does D have properties like T.infinity in the core language to give the infinity of a floating point type, rather than doing it in a library like C++: std::numeric_limits::infinity ?

Let's rephrase that as "if there's a way to express it in the existing language, why build it in to the core language?" In regards to T.infinity:
  1. Building it in to the core language means the core language knows what a floating point infinity is. Being layered in templates, typedefs, casts, const bit patterns, etc., it doesn't know what it is, and is unlikely to give sensible error messages if misused.
  2. A side effect of (1) is it is unlikely to be able to use it effectively in constant folding and other optimizations.
  3. Instantiating templates, loading #include files, etc., all costs compile time and memory.
  4. The worst, though, is the lengths gone to just to get at infinity, implying "the language and compiler don't know anything about IEEE 754 floating point - so it cannot be relied on." And in fact many otherwise excellent C++ compilers do not handle NaN's correctly in floating point comparisons. (Digital Mars C++ does do it correctly.) C++98 doesn't say anything about NaN or Infinity handling in expressions or library functions. So it must be assumed it doesn't work.

To sum up, there's a lot more to supporting NaNs and infinities than having a template that returns a bit pattern. It has to be built in to the compiler's core logic, and it has to permeate all the library code that deals with floating point. And it has to be in the Standard.

To illustrate, if either op1 or op2 or both are NaN, then:

(op1 < op2)

does not yield the same result as:

!(op1 >= op2)

if the NaNs are done correctly.

Why use static if(0) rather than if (0)?

Some limitations are:

  1. if (0) introduces a new scope, static if(...) does not. Why does this matter? It matters if one wants to conditionally declare a new variable:
    static if (...) int x; else long x;
x = 3;
    whereas:
    if (...) int x; else long x;
x = 3;    // error, x is not defined
  2. False static if conditionals don't have to semantically work. For example, it may depend on a conditionally compiled declaration somewhere else:
    static if (...) int x;
int test()
{
    static if (...) return x;
    else return 0;
}
  3. Static if's can appear where only declarations are allowed:
    class Foo
{
    static if (...)
        int x;
}
  4. Static if's can declare new type aliases:
    static if (0 || is(int T)) T x;


Warnings

Last update Sun Dec 30 20:34:43 2012

Warnings

Depending on one's point of view, warnings are either a symptom of broken language design or a useful 'lint' like tool to analyze code and look for potential trouble spots. Most of the time, those trouble spots will be legitimate code intended to be that way. More rarely, it may indicate an unintentional error on the part of the programmer.

Warnings are not a defined part of the D Programming Language. They exist at the discretion of the compiler vendor, and will most likely vary from vendor to vendor. All constructs for which an implementation may generate a warning message are legal D code.

These are the warnings generated by the Digital Mars D compiler when the -w switch is thrown. Most have generated some spirited debate as to whether it should be a warning, an error, and what the correct way to write D code in these situations should be. Since no consensus emerged, they appear as optional warnings, with alternatives on how to write correct code.

warning - implicit conversion of expression expr of type type to type can cause loss of data

D follows the C and C++ rules regarding default integral promotion in expressions. This is done for both compatibility reasons and because modern CPUs are designed to execute such semantics efficiently. These rules also include implicit narrowing rules, where the result of such can be cast back into a smaller type, perhaps losing significant bits in the process:

byte a,b,c;
...
a = b + c;

The b and c are both promoted to type int using the default integral promotion rules. The result of the add is then also int. To be assigned to a, that int gets implicitly converted to a byte.

Whether it is a bug or not in the program depends on if the values for b and c can possibly cause an overflow, and if that overflow matters or not to the algorithm. The warning can be resolved by:

  1. Inserting a cast:
    a = cast(byte)(b + c);
    This eliminates the warning, but since casting is a blunt instrument that bypasses type checking, this can mask another bug that could be introduced if the types of a, b or c change in the future, or if their types are set by a template instantiation. (In generic code, the cast(byte) would probably be cast(typeof(a))).
  2. Changing the type of a to int. This is generally a better solution, but of course may not work if it must be a smaller type, which leads us to:
  3. Doing a runtime check for overflow:
    byte a,b,c;
int tmp;
...
tmp = b + c;
assert(cast(byte)tmp == tmp);
a = cast(byte)tmp;
    This ensures that no significant bits get lost.

Some proposed language solutions are:

  1. Having the compiler automatically insert the equivalent of the option 3 runtime check.
  2. Add a new construct, implicit_cast(type)expression that is a restricted form of the general cast, and will only work where implicit casts would normally be allowed.
  3. Implement the implicit_cast as a template.

warning - array 'length' hides other 'length' name in outer scope

Inside the [ ] of an array indexing expression or slice, the variable length gets defined and set to be the length of that array. The scope of the length is from the opening '[' to the closing ']'.

If length was declared as a variable name in an outer scope, that version may have been intended for use between the [ ]. For example:

char[10] a;
int length = 4;
...
return a[length - 1];	// returns a[9], not a[3]

The warning can be resolved by:

  1. Renaming the outer length to another name.
  2. Replacing the use of length within the [ ] with a.length.
  3. If length is at global or class scope, and that was the one intended to be used, use .length or this.length to disambiguate.

Some proposed language solutions are:

  1. Make the length a special symbol or a keyword instead of an implicitly declared variable.

warning - no return at end of function

Consider the following:

int foo(int k, Collection c)
{
    foreach (int x; c)
    {
    if (x == k)
        return x + 1;
    }
}

and assume that the nature of the algorithm is that x will always be found in c, so the foreach never falls through the bottom of the code. There is no return at the close of the function, because that point is not reachable and any return statement would be dead code. This is perfectly legitimate code. The D compiler, to help with ensuring the robustness of such code, will ensure it is correct by automatically inserting an assert(0); statement at the close of the function. Then, if there's an error in the assumption that the foreach will never fall through, it will be caught at runtime with an obvious assertion failure, which is better than the code just falling off the end causing erratic, arbitrary failures.

D's behavior on this, however, is not common to other languages, and some programmers will be acutely uncomfortable with relying on this, or they wish to see the error at compile time rather than runtime. They wish to see something explicit expressed in the source code that the foreach cannot fall through. Hence the warning.

The warning can be resolved by:

  1. Putting a return statement at the close of the function, returning some arbitrary value (after all, it will never be executed):
    int foo(int k, Collection c)
{
    foreach (int x; c)
    {
    if (x == k)
        return x + 1;
    }
    return 0;	// suppress warning about no return statement
}
    While doing this is surprisingly common, and happens when the programmer is inexperienced or in a hurry, it is a spectacularly bad solution. The trouble happens when the foreach does fall through due to a bug, then instead of the bug being detected, now the function returns an unexpected value, which may cause other problems or go undetected. There's another issue with the maintenance programmer who sees this, and upon analyzing the code's behavior, wonders why there's a return statement that will never be executed. (This can be resolved with comments, but comments are always missing, out of date, or just plain wrong.) Dead code is always a confusing problem to maintenance programming, so deliberately inserting it is a bad idea.
  2. A better solution is to make explicit what the D language does implicitly - put an assert there:
    int foo(int k, Collection c)
{
    foreach (int x; c)
    {
    if (x == k)
        return x + 1;
    }
    assert(0);
}
    Now, if the foreach does fall through, the error will be detected. Furthermore, it is self-documenting.
  3. Another alternative is to do a throw with a custom error class and a more user friendly message:
    int foo(int k, Collection c)
{
    foreach (int x; c)
    {
    if (x == k)
        return x + 1;
    }
    throw new MyErrorClass("fell off the end of foo()");
}

warning - switch statement has no default

Similar to the no return statement warning is the no default in a switch warning. Consider:

switch (i)
{
    case 1: dothis(); break;
    case 2: dothat(); break;
}

According to the D language semantics, this means the only possible values for i are 1 and 2. Any other values represent a bug in the program. To detect this bug, the compiler implements the switch as if it were written:

switch (i)
{
    case 1: dothis(); break;
    case 2: dothat(); break;
    default: throw new SwitchError();
}

This is quite different from C and C++ behavior, which is as if the switch were written:

switch (i)
{
    case 1: dothis(); break;
    case 2: dothat(); break;
    default: break;
}

The potential for bugs with that is high, as it is a common error to accidentally omit a case, or to add a new value in one part of the program and overlook adding a case for it in another part. Although D will catch this error at runtime by throwing an instance of std.switcherr.SwitchError, some prefer at least a warning so such errors can be caught at compile time.

The warning can be resolved by:

  1. Inserting an explict default of the form:
    switch (i)
{
    case 1: dothis(); break;
    case 2: dothat(); break;
    default: assert(0);
}
  2. As in the missing return, a default with a throw of a custom error class can be used.

warning - statement is not reachable

Consider the following code:

int foo(int i)
{
    return i;
    return i + 1;
}

The second return statement is not reachable, i.e. it is dead code. While dead code is poor style in released code, it can legitimately happen a lot when rapidly trying to isolate down a bug or experiment with different bits of code.

The warning can be resolved by:

  1. Commenting out the dead code with /+ ... +/ comments:
    int foo(int i)
{
    return i;
    /+
    return i + 1;
     +/
}
  2. Putting the dead code inside a version(none) conditional:
    int foo(int i)
{
    return i;
    version (none)
    {
    return i + 1;
    }
}
  3. Only compile with warnings enabled when doing release builds.


Memory Management

Last update Sun Dec 30 20:34:42 2012

Memory Management

Most non-trivial programs needs to allocate and free memory. Memory management techniques become more and more important as programs increase in complexity, size, and performance. D offers many options for managing memory.

The three primary methods for allocating memory in D are:

  1. Static data, allocated in the default data segment.
  2. Stack data, allocated on the CPU program stack.
  3. Garbage collected data, allocated dynamically on the garbage collection heap.

The techniques for using them, as well as some advanced alternatives are:

  • Strings (and Array) Copy-on-Write
  • Real Time
  • Smooth Operation
  • Free Lists
  • Reference Counting
  • Explicit Class Instance Allocation
  • Mark/Release
  • RAII (Resource Acquisition Is Initialization)
  • Allocating Class Instances On The Stack
  • Allocating Uninitialized Arrays On The Stack
  • Interrupt Service Routines

Strings (and Array) Copy-on-Write

Consider the case of passing an array to a function, possibly modifying the contents of the array, and returning the modified array. As the contents of an array are accessed through a reference, a crucial issue is who owns the contents of the array? For example, a function to convert an array of characters to upper case:

char[] toupper(char[] s)
{
    int i;

    for (i = 0; i < s.length; i++)
    {
        char c = s[i];
        if ('a' <= c && c <= 'z')
            s[i] = cast(char)(c - ('a' - 'A'));
    }
    return s;
}

Note that the caller's version of s[] is also modified. This may be not at all what was intended, or worse, s[] may be a slice into a read-only section of memory.

If a copy of s[] was always made by toupper(), then that will unnecessarily consume time and memory for strings that are already all upper case.

The solution is to implement copy-on-write, which means that a copy is made only if the string needs to be modified. Some string processing languages do do this as the default behavior, but there is a huge cost to it. The string "abcdeF" will wind up being copied 5 times by the function. To get the maximum efficiency using the protocol, it'll have to be done explicitly in the code. Here's toupper() rewritten to implement copy-on-write in an efficient manner:

char[] toupper(char[] s)
{
    int changed;
    int i;

    changed = 0;
    for (i = 0; i < s.length; i++)
    {
        char c = s[i];
        if ('a' <= c && c <= 'z')
        {
            if (!changed)
            {
                char[] r = new char[s.length];
                r[] = s;
                s = r;
                changed = 1;
            }
            s[i] = cast(char)(c - ('a' - 'A'));
        }
    }
    return s;
}

Copy-on-write is the protocol implemented by array processing functions in the D Phobos runtime library.

Real Time

Real time programming means that a program must be able to guarantee a maximum latency, or time to complete an operation. With most memory allocation schemes, including malloc/free and garbage collection, the latency is theoretically not bound. The most reliable way to guarantee latency is to preallocate all data that will be needed by the time critical portion. If no calls to allocate memory are done, the GC will not run and so will not cause the maximum latency to be exceeded.

Smooth Operation

Related to real time programming is the need for a program to operate smoothly, without arbitrary pauses while the garbage collector stops everything to run a collection. An example of such a program would be an interactive shooter type game. Having the game play pause erratically, while not fatal to the program, can be annoying to the user.

There are several techniques to eliminate or mitigate the effect:

  • Preallocate all data needed before the part of the code that needs to be smooth is run.
  • Manually run a GC collection cycle at points in program execution where it is already paused. An example of such a place would be where the program has just displayed a prompt for user input and the user has not responded yet. This reduces the odds that a collection cycle will be needed during the smooth code.
  • Call std.gc.disable() before the smooth code is run, and std.gc.enable() afterwards. This will cause the GC to favor allocating more memory instead of running a collection pass.

Free Lists

Free lists are a great way to accelerate access to a frequently allocated and discarded type. The idea is simple - instead of deallocating an object when done with it, put it on a free list. When allocating, pull one off the free list first.

class Foo
{
    static Foo freelist;		// start of free list

    static Foo allocate()
    {   Foo f;

    if (freelist)
    {   f = freelist;
        freelist = f.next;
    }
    else
        f = new Foo();
    return f;
    }

    static void deallocate(Foo f)
    {
    f.next = freelist;
    freelist = f;
    }

    Foo next;		// for use by FooFreeList
    ...
}

void test()
{
    Foo f = Foo.allocate();
    ...
    Foo.deallocate(f);
}
Such free list approaches can be very high performance.
  • If used by multiple threads, the allocate() and deallocate() functions need to be synchronized.
  • The Foo constructor is not re-run by allocate() when allocating from the free list, so the allocator may need to reinitialize some of the members.
  • It is not necessary to practice RAII with this, since if any objects are not passed to deallocate() when done, because of a thrown exception, they'll eventually get picked up by the GC anyway.

Reference Counting

The idea behind reference counting is to include a count field in the object. Increment it for each additional reference to it, and decrement it whenever a reference to it ceases. When the count hits 0, the object can be deleted.

D doesn't provide any automated support for reference counting, it will have to be done explicitly.

Win32 COM programming uses the members AddRef() and Release() to maintain the reference counts.

Explicit Class Instance Allocation

D provides a means of creating custom allocators and deallocators for class instances. Normally, these would be allocated on the garbage collected heap, and deallocated when the collector decides to run. For specialized purposes, this can be handled by creating NewDeclarations and DeleteDeclarations. For example, to allocate using the C runtime library's malloc and free:

import std.c.stdlib;
import core.exception;
import core.memory : GC;

class Foo
{
    new(size_t sz)
    {
        void* p;

        p = std.c.stdlib.malloc(sz);

        if (!p)
            throw new OutOfMemoryError();

        GC.addRange(p, sz);
        return p;
    }

    delete(void* p)
    {
        if (p)
        {
            GC.removeRange(p);
            std.c.stdlib.free(p);
        }
    }
}

The critical features of new() are:

  • new() does not have a return type specified, but it is defined to be void*. new() must return a void*.
  • If new() cannot allocate memory, it must not return null, but must throw an exception.
  • The pointer returned from new() must be to memory aligned to the default alignment. This is 8 on win32 systems.
  • The size parameter is needed in case the allocator is called from a class derived from Foo and is a larger size than Foo.
  • A null is not returned if storage cannot be allocated. Instead, an exception is thrown. Which exception gets thrown is up to the programmer, in this case, OutOfMemory() is.
  • When scanning memory for root pointers into the garbage collected heap, the static data segment and the stack are scanned automatically. The C heap is not. Therefore, if Foo or any class derived from Foo using the allocator contains any references to data allocated by the garbage collector, the GC needs to be notified. This is done with the std.gc.addRange() method.
  • No initialization of the memory is necessary, as code is automatically inserted after the call to new() to set the class instance members to their defaults and then the constructor (if any) is run.
The critical features of delete() are:
  • The destructor (if any) has already been called on the argument p, so the data it points to should be assumed to be garbage.
  • The pointer p may be null.
  • If the GC was notified with std.gc.addRange(), a corresponding call to std.gc.removeRange() must happen in the deallocator.
  • If there is a delete(), there should be a corresponding new().

If memory is allocated using class specific allocators and deallocators, careful coding practices must be followed to avoid memory leaks and dangling references. In the presence of exceptions, it is particularly important to practice RAII to prevent memory leaks.

Custom allocators and deallocators can be done for structs and unions, too.

Mark/Release

Mark/Release is equivalent to a stack method of allocating and freeing memory. A ‘stack’ is created in memory. Objects are allocated by simply moving a pointer down the stack. Various points are ‘marked’, and then whole sections of memory are released simply by resetting the stack pointer back to a marked point.

import std.c.stdlib;
import core.exception;
import core.memory : GC;

class Foo
{
    static void[] buffer;
    static int bufindex;
    static const int bufsize = 100;

    static this()
    {
        void* p;
        p = malloc(bufsize);

        if (p is null)
            throw new OutOfMemoryError;

        GC.addRange(p, bufsize);
        buffer = p[0 .. bufsize];
    }

    static ~this()
    {
        if (buffer.length)
        {
            GC.removeRange(buffer.ptr);
            free(buffer.ptr);
            buffer = null;
        }
    }

    new(size_t sz)
    {
        void* p;

        p = &buffer[bufindex];
        bufindex += sz;

        if (bufindex > buffer.length)
            throw new OutOfMemoryError;

        return p;
    }

    delete(void* p)
    {
        assert(0);
    }

    static int mark()
    {
        return bufindex;
    }

    static void release(int i)
    {
        bufindex = i;
    }
}

void main()
{
    int m  = Foo.mark();
    Foo f1 = new Foo;           // allocate
    Foo f2 = new Foo;           // allocate

    Foo.release(m);             // deallocate f1 and f2
}

The allocation of buffer[] itself is added as a region to the GC, so there is no need for a separate call inside Foo.new() to do it.

RAII (Resource Acquisition Is Initialization)

RAII techniques can be useful in avoiding memory leaks when using explicit allocators and deallocators. Adding the scope attribute to such classes can help.

Allocating Class Instances On The Stack

Class instances are normally allocated on the garbage collected heap. However, if they:

  • are allocated as local symbols in a function and
  • are allocated using new and
  • use new with no arguments (constructor arguments are allowed) and
  • have the scope storage class

then they are allocated on the stack. This is more efficient than doing an allocate/free cycle on the instance. But be careful that any reference to the object does not survive the return of the function.

class C { ... }

scope c = new C();	// c is allocated on the stack
scope c2 = new C(5);    // allocated on stack
scope c3 = new(5) C();  // allocated by a custom allocator

If the class has a destructor, then that destructor is guaranteed to be run when the class object goes out of scope, even if the scope is exited via an exception.

Allocating Uninitialized Arrays On The Stack

Arrays are always initialized in D. So, the following declaration:

void foo()
{   byte[1024] buffer;

    fillBuffer(buffer);
    ...
}

will not be as fast as it might be since the buffer[] contents are always initialized. If careful profiling of the program shows that this initialization is a speed problem, it can be eliminated using a VoidInitializer:

void foo()
{   byte[1024] buffer = void;

    fillBuffer(buffer);
    ...
}

Uninitialized data on the stack comes with some caveats that need to be carefully evaluated before using:

  • The uninitialized data that is on the stack will get scanned by the garbage collector looking for any references to allocated memory. Since the uninitialized data consists of old D stack frames, it is highly likely that some of that garbage will look like references into the GC heap, and the GC memory will not get freed. This problem really does happen, and can be pretty frustrating to track down.
  • It's possible for a function to pass out of it a reference to data on that function's stack frame. By then allocating a new stack frame over the old data, and not initializing, the reference to the old data may still appear to be valid. The program will then behave erratically. Initializing all data on the stack frame will greatly increase the probability of forcing that bug into the open in a repeatable manner.
  • Uninitialized data can be a source of bugs and trouble, even when used correctly. One design goal of D is to improve reliability and portability by eliminating sources of undefined behavior, and uninitialized data is one huge source of undefined, unportable, erratic and unpredictable behavior. Hence this idiom should only be used after other opportunities for speed optimization are exhausted and if benchmarking shows that it really does speed up the overall execution.

Interrupt Service Routines

When the garbage collector does a collection pass, it must pause all running threads in order to scan their stacks and register contents for references to GC allocated objects. If an ISR (Interrupt Service Routine) thread is paused, this can break the program.

Therefore, the ISR thread should not be paused. Threads created with the core.thread functions will be paused. But threads created with C's _beginthread() or equivalent won't be, the GC won't know they exist.

For this to work successfully:

  • The ISR thread cannot allocate any memory using the GC. This means that the global new cannot be used. Nor can dynamic arrays be resized, nor can any elements be added to associative arrays. Any use of the D runtime library should be examined for any possibility of allocating GC memory - or better yet, the ISR should not call any D runtime library functions at all.
  • The ISR cannot hold the sole reference to any GC allocated memory, otherwise the GC may free the memory while the ISR is still using it. The solution is to have one of the paused threads hold a reference to it too, or store a reference to it in global data.


Exception Safety

Last update Sun Dec 30 20:34:43 2012

Exception Safe Programming

Exception safe programming is programming so that if any piece of code that might throw an exception does throw an exception, then the state of the program is not corrupted and resources are not leaked. Getting this right using traditional methods often results in complex, unappealing and brittle code. As a result, exception safety often is either buggy or simply ignored for the sake of expediency.

Example

For example, if there's a Mutex m that must be acquired and held for a few statements, then released:
void abc()
{
    Mutex m = new Mutex;
    lock(m);	// lock the mutex
    foo();	// do processing
    unlock(m);	// unlock the mutex
}

If foo() throws an exception, then abc() exits via exception unwinding, unlock(m) is never called and the Mutex is not released. This is a fatal problem with this code.

The RAII (Resource Acquisition Is Initialization) idiom and the try-finally statement form the backbone of the traditional approaches to writing exception safe programming.

RAII is scoped destruction, and the example can be fixed by providing a Lock class with a destructor that gets called upon the exit of the scope:

class Lock
{
    Mutex m;

    this(Mutex m)
    {
    this.m = m;
    lock(m);
    }

    ~this()
    {
    unlock(m);
    }
}

void abc()
{
    Mutex m = new Mutex;
    scope L = new Lock(m);
    foo();	// do processing
}
If abc() is exited normally or via an exception thrown from foo(), L gets its destructor called and the mutex is unlocked. The try-finally solution to the same problem looks like:
void abc()
{
    Mutex m = new Mutex;
    lock(m);	// lock the mutex
    try
    {
    foo();	// do processing
    }
    finally
    {
    unlock(m);	// unlock the mutex
    }
}

Both solutions work, but both have drawbacks. The RAII solution often requires the creation of an extra dummy class, which is both a lot of lines of code to write and a lot of clutter obscuring the control flow logic. This is worthwhile to manage resources that must be cleaned up and that appear more than once in a program, but it is clutter when it only needs to be done once. The try-finally solution separates the unwinding code from the setup, and it can often be a visually large separation. Closely related code should be grouped together.

The scope exit statement is an easier approach:

void abc()
{
    Mutex m = new Mutex;

    lock(m);	// lock the mutex
    scope(exit) unlock(m);	// unlock on leaving the scope

    foo();	// do processing
}
The scope(exit) statement is executed at the closing curly brace upon normal execution, or when the scope is left due to an exception having been thrown. It places the unwinding code where it aesthetically belongs, next to the creation of the state that needs unwinding. It's far less code to write than either the RAII or try-finally solutions, and doesn't require the creation of dummy classes.

Example

The next example is in a class of problems known as transaction processing:
Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    b = dobar();

    return Transaction(f, b);
}

Both dofoo() and dobar() must succeed, or the transaction has failed. If the transaction failed, the data must be restored to the state where neither dofoo() nor dobar() have happened. To support that, dofoo() has an unwind operation, dofoo_undo(Foo f) which will roll back the creation of a Foo.

With the RAII approach:

class FooX
{
    Foo f;
    bool commit;

    this()
    {
    f = dofoo();
    }

    ~this()
    {
    if (!commit)
        dofoo_undo(f);
    }
}

Transaction abc()
{
    scope f = new FooX();
    Bar b = dobar();
    f.commit = true;
    return Transaction(f.f, b);
}
With the try-finally approach:
Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    try
    {
    b = dobar();
    return Transaction(f, b);
    }
    catch (Object o)
    {
    dofoo_undo(f);
    throw o;
    }
}

These work too, but have the same problems. The RAII approach involves the creation of dummy classes, and the obtuseness of moving some of the logic out of the abc() function. The try-finally approach is wordy even with this simple example; try writing it if there are more than two components of the transaction that must succeed. It scales poorly.

The scope(failure) statement solution looks like:

Transaction abc()
{
    Foo f;
    Bar b;

    f = dofoo();
    scope(failure) dofoo_undo(f);

    b = dobar();

    return Transaction(f, b);
}
The dofoo_undo(f) only is executed if the scope is exited via an exception. The unwinding code is minimal and kept aesthetically where it belongs. It scales up in a natural way to more complex transactions:
Transaction abc()
{
    Foo f;
    Bar b;
    Def d;

    f = dofoo();
    scope(failure) dofoo_undo(f);

    b = dobar();
    scope(failure) dobar_unwind(b);

    d = dodef();

    return Transaction(f, b, d);
}

Example

The next example involves temporarily changing the state of some object. Suppose there's a class data member verbose, which controls the emission of messages logging the activity of the class. Inside one of the methods, verbose needs to be turned off because there's a loop that would otherwise cause a blizzard of messages to be output:
class Foo
{
    bool verbose;	// true means print messages, false means silence
    ...
    bar()
    {
    auto verbose_save = verbose;
    verbose = false;
    ... lots of code ...
    verbose = verbose_save;
    }
}
There's a problem if Foo.bar() exits via an exception - the verbose flag state is not restored. That's easily fixed with scope(exit):
class Foo
{
    bool verbose;	// true means print messages, false means silence
    ...
    bar()
    {
    auto verbose_save = verbose;
    verbose = false;
    scope(exit) verbose = verbose_save;

    ...lots of code...
    }
}

It also neatly solves the problem if ...lots of code... goes on at some length, and in the future a maintenance programmer inserts a return statement in it, not realizing that verbose must be reset upon exit. The reset code is where it belongs conceptually, rather than where it gets executed (an analogous case is the continuation expression in a ForStatement). It works whether the scope is exited by a return, break, goto, continue, or exception.

The RAII solution would be to try and capture the false state of verbose as a resource, an abstraction that doesn't make much sense. The try-finally solution requires arbitrarily large separation between the conceptually linked set and reset code, besides requiring the addition of an irrelevant scope.

Example

Here's another example of a multi-step transaction, this time for an email program. Sending an email consists of two operations:
  1. Perform the SMTP send operation.
  2. Copy the email to the "Sent" folder, which in POP is on the local disk, and in IMAP is also remote.

Messages should not appear in "Sent" that haven't been actually sent, and sent messages must actually appear in "Sent".

Operation (1) is not undoable because it's a well-known distributed computing issue. Operation (2) is undoable with some degree of reliability. So we break the job down into three steps:

  1. Copy the message to "Sent" with a changed title "[Sending] <Subject>". This operation ensures there's space in the client's IMAP account (or on the local disk), the rights are proper, the connection exists and works, etc.
  2. Send the message via SMTP.
  3. If sending fails, delete the message from "Sent". If the message succeeds, change its title from "[Sending] <Subject>" to "<Subject>". Both of these operation have a high probability to succeed. If the folder is local, the probability of success is very high. If the folder is remote, probability is still vastly higher than that of step (1) because it doesn't involve an arbitrarily large data transfer.
class Mailer
{
    void Send(Message msg)
    {
    {
        char[] origTitle = msg.Title();
        scope(exit) msg.SetTitle(origTitle);
        msg.SetTitle("[Sending] " ~ origTitle);
        Copy(msg, "Sent");
    }
    scope(success) SetTitle(msg.ID(), "Sent", msg.Title);
    scope(failure) Remove(msg.ID(), "Sent");
    SmtpSend(msg);	// do the least reliable part last
    }
}
This is a compelling solution to a complex problem. Rewriting it with RAII would require two extra silly classes, MessageTitleSaver and MessageRemover. Rewriting the example with try-finally would require nested try-finally statements or use of an extra variable to track state evolution.

Example

Consider giving feedback to the user about a lengthy operation (mouse changes to an hourglass, window title is red/italicized, ...). With scope(exit) that can be easily done without needing to make an artificial resource out of whatever UI state element used for the cues:
void LongFunction()
{
    State save = UIElement.GetState();
    scope(exit) UIElement.SetState(save);
    ...lots of code...
}
Even more so, scope(success) and scope(failure) can be used to give an indication if the operation succeeded or if an error occurred:
void LongFunction()
{
    State save = UIElement.GetState();
    scope(success) UIElement.SetState(save);
    scope(failure) UIElement.SetState(Failed(save));
    ...lots of code...
}

When to use RAII, try-catch-finally, and Scope

RAII is for managing resources, which is different from managing state or transactions. try-catch is still needed, as scope doesn't catch exceptions. It's try-finally that becomes redundant.

Acknowledgements

Andrei Alexandrescu argued about the usefulness of these constructs on the Usenet and also defined their semantics in terms of try/catch/finally in a series of posts to comp.lang.c++.moderated under the title A safer/better C++? starting Dec 6, 2005. D implements the idea with a slightly modified syntax following its creator's experiments with the feature and useful suggestions from the D programmer community, especially Dawid Ciezarkiewicz and Chris Miller.

I am indebted to Scott Meyers for teaching me about exception safe programming.

References:

  1. Generic<Programming>: Change the Way You Write Exception-Safe Code Forever by Andrei Alexandrescu and Petru Marginean
  2. "Item 29: Strive for exception-safe code" in Effective C++ Third Edition, pg. 127 by Scott Meyers


Templates Revisited

Last update Sun Dec 30 20:34:43 2012

Templates Revisited

by Walter Bright, http://www.digitalmars.com/d

"What I am going to tell you about is what we teach our programming students in the third or fourth year of graduate school... It is my task to convince you not to turn away because you don't understand it. You see my programming students don't understand it... That is because I don't understand it. Nobody does."
-- Richard Deeman

Abstract

Templates in C++ have evolved from little more than token substitution into a programming language in itself. Many useful aspects of C++ templates have been discovered rather than designed. A side effect of this is that C++ templates are often criticized for having an awkward syntax, many arcane rules, and being very difficult to implement properly. What might templates look like if one takes a step back, looks at what templates can do and what uses they are put to, and redesign them? Can templates be powerful, aesthetically pleasing, easy to explain and straightforward to implement? This article takes a look at an alternative design of templates in the D Programming Language [1].

Similarities

  • compile time semantics
  • function templates
  • class templates
  • type parameters
  • value parameters
  • template parameters
  • partial and explicit specialization
  • type deduction
  • implicit function template instantiation
  • SFINAE (Substitution Failure Is Not An Error)

Argument Syntax

The first thing that comes to mind is the use of < > to enclose parameter lists and argument lists. < > has a couple serious problem, however. They are ambiguous with operators <, >, and >>. This means that expressions like:

a<b,c>d;
and:
a<b<c>>d;

are syntactically ambiguous, both to the compiler and the programmer. If you run across a<b,c>d; in unfamiliar code, you've got to slog through an arbitrarily large amount of declarations and .h files to figure out if it is a template or not. How much effort has been expended by programmers, compiler writers, and language standard writers to deal with this?

There's got to be a better way. D solves it by noticing that ! is not used as a binary operator, so replacing:

a<b,c>

with:

a!(b,c)

is syntactically unambiguous. This makes it easy to parse, easy to generate reasonable error messages for, and makes it easy for someone inspecting the code to determine that yes, a must be a template.

Template Definition Syntax

C++ can define two broad types of templates: class templates, and function templates. Each template is written independently, even if they are closely related:

template<class T, class U> class Bar { ... };

template<class T, class U> T foo(T t, U u) { ... }

template<class T, class U> static T abc;

POD (Plain Old Data, as in C style) structs bring together related data declarations, classes bring together related data and function declarations, but there's nothing to logically group together templates that are to be instantiated together. In D, we can write:

template Foo(T, U)
{
  class Bar { ... }

  T foo(T t, U u) { ... }

  T abc;

  typedef T* Footype;	// any declarations can be templated
}

The Foo forms a name space for the templates, which are accessed by, for example:

Foo!(int,char).Bar b;
Foo!(int,char).foo(1,2);
Foo!(int,char).abc = 3;

Of course, this can get a little tedious, so one can use an alias for a particular instantiation:

alias Foo!(int,char) f;
f.Bar b;
f.foo(1,2);
f.abc = 3;

For class templates, there's an even simpler syntax. A class is defined like:

class Abc
{
    int t;
    ...
}

This can be turned into a template by just adding a parameter list:

class Abc(T)
{
    T t;
    ...
}

Template Declaration, Definition, and Export

C++ templates can be in the form of a template declaration, a template definition, and an exported template. Because D has a true module system, rather than textual #include files, there are only template definitions in D. The need for template declarations and export is irrelevant. For example, given a template definition in module A:

module A;

template Foo(T)
{
    T bar;
}

it can be accessed from module B like:

module B;

import A;

void test()
{
    A.Foo!(int).bar = 3;
}

As usual, an alias can be used to simplify access:

module B;

import A;
alias A.Foo!(int).bar bar;

void test()
{
    bar = 3;
}

Template Parameters

C++ template parameters can be:

  • types
  • integral values
  • static/global addresses
  • template names

D template parameters can be:

  • types
  • integral values
  • floating point values
  • string literals
  • templates
  • or any symbol

Each can have default values, and type parameters can have (a limited form of) constraints:

class B { ... }
interface I { ... }

class Foo(
  R,            // R can be any type
  P:P*,         // P must be a pointer type
  T:int,        // T must be int type
  S:T*,         // S must be pointer to T
  C:B,          // C must be of class B or derived
                // from B
  U:I,          // U must be a class that
                // implements interface I
  char[] string = "hello",
                // string literal,
                // default is "hello"
  alias A = B   // A is any symbol
                // (including template symbols),
                // defaulting to B
  )
{
    ...
}

Specialization

Partial and explicit specialization work as they do in C++, except that there is no notion of a 'primary' template. All the templates with the same name are examined upon template instantiation, and the one with the best fit of arguments to parameters is instantiated.

template Foo(T) ...
template Foo(T:T*) ...
template Foo(T, U:T) ...
template Foo(T, U) ...
template Foo(T, U:int) ...

Foo!(long)       // picks Foo(T)
Foo!(long[])     // picks Foo(T), T is long[]
Foo!(int*)       // picks Foo(T*), T is int
Foo!(long,long)  // picks Foo(T, T)
Foo!(long,short) // picks Foo(T, U)
Foo!(long,int)   // picks Foo(T, U:int)
Foo!(int,int)    // ambiguous - Foo(T, U:T)
                 // or Foo(T, U:int)

Two Level Name Lookup

C++ has some unusual rules for name lookup inside templates, such as not looking inside base classes, not allowing scoped redeclaration of template parameter names, and not considering overloads that happen after the point of definition (this example is derived from one in the C++98 Standard):

int g(double d) { return 1; }

typedef double A;

template<class T> B
{
  typedef int A;
};

template<class T> struct X : B<T>
{
  A a;              // a has type double
  int T;            // error, T redeclared
  int foo()
  {  char T;        // error, T redeclared
     return g(1);   // always returns 1
  }
};

int g(int i) { return 2; }	// this definition not seen by X

Scoped lookup rules in D match the rules for the rest of the language:

int g(double d) { return 1; }

typedef double A;

class B(T)
{
  typedef int A;
}

class X(T) : B!(T)
{
  A a;             // a has type int
  int T;           // ok, T redeclared as int
  int foo()
  {   char T;      // ok, T redeclared as char
     return g(1);  // always returns 2
  }
};

int g(int i) { return 2; }	// functions can be forward referenced

Template Recursion

Template recursion combined with specialization means that C++ templates actually form a programming language, although certainly an odd one. Consider a set of templates that computes a factorial at run time. Like "hello world" programs, factorial is the canonical example of template metaprogramming:

template<int n> class factorial
{
  public:
    enum
    {
      result = n * factorial<n - 1>::result
    };
};

template<> class factorial<1>
{
  public:
    enum { result = 1 };
};

void test()
{
  // prints 24
  printf("%d\n", factorial<4>::result);
}

Recursion works as well in D, though with significantly less typing:

template factorial(int n)
{
  const factorial = n * factorial!(n-1);
}

template factorial(int n : 1)
{
  const factorial = 1;
}

void test()
{
  writefln(factorial!(4));  // prints 24
}

Through using the static if construct it can be done in just one template:

template factorial(int n)
{
  static if (n == 1)
    const factorial = 1;
  else
    const factorial = n * factorial!(n-1);
}

reducing 13 lines of code to an arguably much cleaner 7 lines. static if's are the equivalent of C++'s #if. But #if cannot access template arguments, so all template conditional compilation must be handled with partial and explicitly specialized templates. static if dramatically simplifies such constructions.

D can make this even simpler. Value generating templates such as the factorial one are possible, but it's easier to just write a function that can be computed at compile time:

int factorial(int n)
{
  if (n == 1)
    return 1;
  else
    return n * factorial(n - 1);
}

static int x = factorial(5);  // x is statically initialized to 120

SFINAE (Substitution Failure Is Not An Error)

This determines if the template's argument type is a function, from "C++ Templates: The Complete Guide", Vandevoorde & Josuttis pg. 353:

template<U> class IsFunctionT
{
  private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template static One test(...);
    template static Two test(U (*)[1]);
  public:
    enum {
      Yes = sizeof(IsFunctionT::test(0)) == 1
    };
};

void test()
{
  typedef int (fp)(int);

  assert(IsFunctionT<fp>::Yes == 1);
}

Template IsFunctionT relies on two side effects to achieve its result. First, it relies on arrays of functions being an invalid C++ type. Thus, if U is a function type, the second test will not be selected since to do so would cause an error (SFINAE (Substitution Failure Is Not An Error)). The first test will be selected. If U is not a function type, the second test is a better fit than ... . Next, it is determined which test was selected by examining the size of the return value, i.e. sizeof(One) or sizeof(Two). Unfortunately, template metaprogramming in C++ often seems to be relying on side effects rather than being able to expressly code what is desired.

In D this can be written:

template IsFunctionT(T)
{
  static if ( is(T[]) )
    const int IsFunctionT = 0;
  else
    const int IsFunctionT = 1;
}

void test()
{
  alias int fp(int);

  assert(IsFunctionT!(fp) == 1);
}

The is(T[]) is the equivalent of SFINAE (Substitution Failure Is Not An Error). It tries to build an array of T, and if T is a function type, it is an array of functions. Since this is an invalid type, the T[] fails and is(T[]) returns false.

Although SFINAE (Substitution Failure Is Not An Error) can be used, the is expressions can test a type directly, so it isn't even necessary to use a template to ask questions about a type:

void test()
{
  alias int fp(int);

  assert( is(fp == function) );
}

Template Metaprogramming With Floats

Let's move on to things that are impractical with templates in C++. For example, this template returns the square root of real number x using the Babylonian method:

import std.stdio;

template sqrt(real x, real root = x/2, int ntries = 0)
{
  static if (ntries == 5)
    // precision doubles with each iteration,
    // 5 should be enough
    const sqrt = root;
  else static if (root * root - x == 0)
    const sqrt = root;  // exact match
  else
    // iterate again
    const sqrt = sqrt!(x, (root+x/root)/2, ntries+1);
}

void main()
{
    real x = sqrt!(2);
    writefln("%.20g", x); // 1.4142135623730950487
}

Literal square roots are often needed for speed reasons in other runtime floating point computations, such as computing the gamma function. These template floating point algorithms need not be efficient as they are computed at compile time, they only need to be accurate.

Much more complex templates can be built, for example, Don Clugston has written a template to compute π at compile time. [2]

Again, we can just do this with a function that can be executed at compile time:

real sqrt(real x)
{
    real root = x / 2;
    for (int ntries = 0; ntries < 5; ntries++)
    {
    if (root * root - x == 0)
        break;
    root = (root + x / root) / 2;
    }
    return root;
}
static y = sqrt(10);   // y is statically initialized to 3.16228

Template Metaprogramming With Strings

Even more interesting things can be done with strings. This example converts an integer to a string at compile time:

template decimalDigit(int n)	// [3]
{
  const char[] decimalDigit = "0123456789"[n..n+1];
}

template itoa(long n)
{
  static if (n < 0)
     const char[] itoa = "-" ~ itoa!(-n);
  else static if (n < 10)
     const char[] itoa = decimalDigit!(n);
  else
     const char[] itoa = itoa!(n/10L) ~ decimalDigit!(n%10L);
}

char[] foo()
{
  return itoa!(264);   // returns "264"
}

This template will compute the hash of a string literal:

template hash(char [] s, uint sofar=0)
{
   static if (s.length == 0)
      const hash = sofar;
   else
      const hash = hash!(s[1 .. length], sofar * 11 + s[0]);
}

uint foo()
{
    return hash!("hello world");
}

Regular Expression Compiler

How do D templates fare with something much more significant, like a regular expression compiler? Eric Niebler has written one for C++ that relies on expression templates. [4] The problem with using expression templates is that one is restricted to using only C++ operator syntax and precedence. Hence, regular expressions using expression templates don't look like regular expressions, they look like C++ expressions. Eric Anderton has written one for D that relies on the ability of templates to parse strings. [5] This means that, within the strings, one can use the expected regular expression grammar and operators.

The regex compiler templates parse the regex string argument, pulling off tokens one by one from the front, and instantiating custom template functions for each token predicate, eventually combining them all into one function that directly implements the regular expression. It even gives reasonable error messages for syntax errors in the regular expression.

Calling that function with an argument of a string to match returns an array of matching strings:

import std.stdio;
import regex;

void main()
{
    auto exp = &regexMatch!(r"[a-z]*\s*\w*");
    writefln("matches: %s", exp("hello    world"));
}

What follows is a cut-down version of Eric Anderton's regex compiler. It is just enough to compile the regular expression above, serving to illustrate how it is done.

module regex;

const int testFail = -1;

/**
 * Compile pattern[] and expand to a custom generated
 * function that will take a string str[] and apply the
 * regular expression to it, returning an array of matches.
 */

template regexMatch(char[] pattern)
{
  char[][] regexMatch(char[] str)
  {
    char[][] results;
    int n = regexCompile!(pattern).fn(str);
    if (n != testFail && n > 0)
      results ~= str[0..n];
    return results;
  }
}

/******************************
 * The testXxxx() functions are custom generated by templates
 * to match each predicate of the regular expression.
 *
 * Params:
 *	char[] str	the input string to match against
 *
 * Returns:
 *	testFail	failed to have a match
 *	n >= 0		matched n characters
 */

/// Always match
template testEmpty()
{
  int testEmpty(char[] str) { return 0; }
}

/// Match if testFirst(str) and testSecond(str) match
template testUnion(alias testFirst, alias testSecond)
{
  int testUnion(char[] str)
  {
    int n1 = testFirst(str);
    if (n1 != testFail)
    {
      int n2 = testSecond(str[n1 .. $]);
      if (n2 != testFail)
        return n1 + n2;
    }
    return testFail;
  }
}

/// Match if first part of str[] matches text[]
template testText(char[] text)
{
  int testText(char[] str)
  {
    if (str.length &&
        text.length <= str.length &&
        str[0..text.length] == text
       )
      return text.length;
    return testFail;
  }
}

/// Match if testPredicate(str) matches 0 or more times
template testZeroOrMore(alias testPredicate)
{
  int testZeroOrMore(char[] str)
  {
    if (str.length == 0)
      return 0;
    int n = testPredicate(str);
    if (n != testFail)
    {
      int n2 = testZeroOrMore!(testPredicate)(str[n .. $]);
      if (n2 != testFail)
        return n + n2;
      return n;
    }
    return 0;
  }
}

/// Match if term1[0] <= str[0] <= term2[0]
template testRange(char[] term1, char[] term2)
{
  int testRange(char[] str)
  {
    if (str.length && str[0] >= term1[0]
                   && str[0] <= term2[0])
      return 1;
    return testFail;
  }
}

/// Match if ch[0]==str[0]
template testChar(char[] ch)
{
  int testChar(char[] str)
  {
    if (str.length && str[0] == ch[0])
      return 1;
    return testFail;
  }
}

/// Match if str[0] is a word character
template testWordChar()
{
  int testWordChar(char[] str)
  {
    if (str.length &&
        (
         (str[0] >= 'a' && str[0] <= 'z') ||
         (str[0] >= 'A' && str[0] <= 'Z') ||
         (str[0] >= '0' && str[0] <= '9') ||
         str[0] == '_'
        )
       )
    {
      return 1;
    }
    return testFail;
  }
}

/*****************************************************/

/**
 * Returns the front of pattern[] up until
 * the end or a special character.
 */

template parseTextToken(char[] pattern)
{
  static if (pattern.length > 0)
  {
    static if (isSpecial!(pattern))
      const char[] parseTextToken = "";
    else
      const char[] parseTextToken =
           pattern[0..1] ~ parseTextToken!(pattern[1..$]);
  }
  else
    const char[] parseTextToken="";
}

/**
 * Parses pattern[] up to and including terminator.
 * Returns:
 *	token[]	 	everything up to terminator.
 *	consumed	number of characters in pattern[] parsed
 */
template parseUntil(char[] pattern,char terminator,bool fuzzy=false)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == '\\')
    {
      static if (pattern.length > 1)
      {
        const char[] nextSlice = pattern[2 .. $];
        alias parseUntil!(nextSlice,terminator,fuzzy) next;
        const char[] token = pattern[0 .. 2] ~ next.token;
        const uint consumed = next.consumed+2;
      }
      else
      {
        pragma(msg,"Error: expected character to follow \\");
        static assert(false);
      }
    }
    else static if (pattern[0] == terminator)
    {
      const char[] token="";
      const uint consumed = 1;
    }
    else
    {
      const char[] nextSlice = pattern[1 .. $];
      alias parseUntil!(nextSlice,terminator,fuzzy) next;
      const char[] token = pattern[0..1] ~ next.token;
      const uint consumed = next.consumed+1;
    }
  }
  else static if (fuzzy)
  {
    const char[] token = "";
    const uint consumed = 0;
  }
  else
  {
    pragma(msg,"Error: expected " ~
               terminator ~
               " to terminate group expression");
    static assert(false);
  }
}

/**
 * Parse contents of character class.
 * Params:
 *   pattern[] = rest of pattern to compile
 * Output:
 *   fn       = generated function
 *   consumed = number of characters in pattern[] parsed
 */

template regexCompileCharClass2(char[] pattern)
{
  static if (pattern.length > 0)
  {
    static if (pattern.length > 1)
    {
      static if (pattern[1] == '-')
      {
        static if (pattern.length > 2)
        {
          alias testRange!(pattern[0..1], pattern[2..3]) termFn;
          const uint thisConsumed = 3;
          const char[] remaining = pattern[3 .. $];
        }
        else // length is 2
        {
          pragma(msg,
            "Error: expected char following '-' in char class");
          static assert(false);
        }
      }
      else // not '-'
      {
        alias testChar!(pattern[0..1]) termFn;
        const uint thisConsumed = 1;
        const char[] remaining = pattern[1 .. $];
      }
    }
    else
    {
      alias testChar!(pattern[0..1]) termFn;
      const uint thisConsumed = 1;
      const char[] remaining = pattern[1 .. $];
    }
    alias regexCompileCharClassRecurse!(termFn,remaining) recurse;
    alias recurse.fn fn;
    const uint consumed = recurse.consumed + thisConsumed;
  }
  else
  {
    alias testEmpty!() fn;
    const uint consumed = 0;
  }
}

/**
 * Used to recursively parse character class.
 * Params:
 *  termFn = generated function up to this point
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function including termFn and
 *       parsed character class
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompileCharClassRecurse(alias termFn,char[] pattern)
{
  static if (pattern.length > 0 && pattern[0] != ']')
  {
    alias regexCompileCharClass2!(pattern) next;
    alias testOr!(termFn,next.fn,pattern) fn;
    const uint consumed = next.consumed;
  }
  else
  {
    alias termFn fn;
    const uint consumed = 0;
  }
}

/**
 * At start of character class. Compile it.
 * Params:
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompileCharClass(char[] pattern)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == ']')
    {
      alias testEmpty!() fn;
      const uint consumed = 0;
    }
    else
    {
      alias regexCompileCharClass2!(pattern) charClass;
      alias charClass.fn fn;
      const uint consumed = charClass.consumed;
    }
  }
  else
  {
    pragma(msg,"Error: expected closing ']' for character class");
    static assert(false);
  }
}

/**
 * Look for and parse '*' postfix.
 * Params:
 *  test = function compiling regex up to this point
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompilePredicate(alias test, char[] pattern)
{
  static if (pattern.length > 0 && pattern[0] == '*')
  {
    alias testZeroOrMore!(test) fn;
    const uint consumed = 1;
  }
  else
  {
    alias test fn;
    const uint consumed = 0;
  }
}

/**
 * Parse escape sequence.
 * Params:
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function
 *  consumed = number of characters in pattern[] parsed
 */

template regexCompileEscape(char[] pattern)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == 's')
    {
      // whitespace char
      alias testRange!("\x00","\x20") fn;
    }
    else static if (pattern[0] == 'w')
    {
      //word char
      alias testWordChar!() fn;
    }
    else
    {
      alias testChar!(pattern[0 .. 1]) fn;
    }
    const uint consumed = 1;
  }
  else
  {
    pragma(msg,"Error: expected char following '\\'");
    static assert(false);
  }
}

/**
 * Parse and compile regex represented by pattern[].
 * Params:
 *  pattern[] = rest of pattern to compile
 * Output:
 *  fn = generated function
 */

template regexCompile(char[] pattern)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == '[')
    {
      const char[] charClassToken =
          parseUntil!(pattern[1 .. $],']').token;
      alias regexCompileCharClass!(charClassToken) charClass;
      const char[] token = pattern[0 .. charClass.consumed+2];
      const char[] next = pattern[charClass.consumed+2 .. $];
      alias charClass.fn test;
    }
    else static if (pattern[0] == '\\')
    {
      alias regexCompileEscape!(pattern[1..pattern.length]) escapeSequence;
      const char[] token = pattern[0 .. escapeSequence.consumed+1];
      const char[] next =
          pattern[escapeSequence.consumed+1 .. $];
      alias escapeSequence.fn test;
    }
    else
    {
      const char[] token = parseTextToken!(pattern);
      static assert(token.length > 0);
      const char[] next = pattern[token.length .. $];
      alias testText!(token) test;
    }

    alias regexCompilePredicate!(test, next) term;
    const char[] remaining = next[term.consumed .. next.length];

    alias regexCompileRecurse!(term,remaining).fn fn;
  }
  else
    alias testEmpty!() fn;
}

template regexCompileRecurse(alias term,char[] pattern)
{
  static if (pattern.length > 0)
  {
    alias regexCompile!(pattern) next;
    alias testUnion!(term.fn, next.fn) fn;
  }
  else
    alias term.fn fn;
}

/// Utility function for parsing
template isSpecial(char[] pattern)
{
  static if (
    pattern[0] == '*' ||
    pattern[0] == '+' ||
    pattern[0] == '?' ||
    pattern[0] == '.' ||
    pattern[0] == '[' ||
    pattern[0] == '{' ||
    pattern[0] == '(' ||
    pattern[0] == ')' ||
    pattern[0] == '$' ||
    pattern[0] == '^' ||
    pattern[0] == '\\'
  )
    const isSpecial = true;
  else
    const isSpecial = false;
}

More Template Metaprogramming

  1. Tomasz Stachowiak's compile time raytracer.
  2. Don Clugston's compile time 99 Bottles of Beer.

References

[1] D programming language, see http://www.digitalmars.com/d/

[2] Don Clugston's π calculator, see http://trac.dsource.org/projects/ddl/browser/trunk/meta/demo/calcpi.d

[3] Don Clugston's decimaldigit and itoa, see http://trac.dsource.org/projects/ddl/browser/trunk/meta/conv.d

[4] Eric Niebler's Boost.Xpressive regular expression template library is at http://boost-sandbox.sourceforge.net/libs/xpressive/doc/html/index.html

[5] Eric Anderton's Regular Expression template library for D is at http://trac.dsource.org/projects/ddl/browser/trunk/meta/regex.d

Acknowledgements

I gratefully acknowledge the inspiration and assistance of Don Clugston, Eric Anderton and Matthew Wilson.


Regular Expressions

Last update Sun Dec 30 20:34:43 2012

Regular Expressions

Regular expressions are a powerful tool for pattern matching on strings of text. They are built in to the core of languages like Perl, Ruby, and Javascript. Perl and Ruby are particulary reknowned for adroitly handling regular expressions. So why aren't they part of the D core language? Read on and see how they're done in D compared with Ruby.

This article explains how to use regular expressions in D. It doesn't explain regular expressions themselves, after all, people have written entire books on that topic. D's specific implementation of regular expressions is entirely contained in the Phobos library module std.regexp. For a more advanced treatment of using regular expressions in conjuction with template metaprogramming, see Templates Revisited.

In Ruby a regular expression can be created as a special literal:

r = /pattern/
s = /p[1-5]\s*/

D doesn't have special literals for them, but they can be created:

r = RegExp("pattern");
s = RegExp(r"p[1-5]\s*");

If the pattern contains backslash characters \, wysiwyg string literals are used, which have the 'r' prefix to the string. r and s are of type RegExp, but we can use type inference to declare and assign them automatically:

auto r = RegExp("pattern");
auto s = RegExp(r"p[1-5]\s*");

To check for a match of a string s with a regular expression in Ruby, use the =~ operator, which returns the index of the first match:

s = "abcabcabab"
s =~ /b/   /* match, returns 1 */
s =~ /f/   /* no match, returns nil */

In D this looks like:

auto s = "abcabcabab";
std.regexp.find(s, "b");    /* match, returns 1 */
std.regexp.find(s, "f");    /* no match, returns -1 */

Note the equivalence to std.string.find, which searches for substring matches rather than regular expression matches.

The Ruby =~ operator sets some implicitly defined variables based on the result:

s = "abcdef"
if s =~ /c/
    "#{$`}[#{$&}]#{$'}"   /* generates string ab[c]def

The function std.regexp.search() returns a RegExp object describing the match, which can be exploited:

auto m = std.regexp.search("abcdef", "c");
if (m)
    writefln("%s[%s]%s", m.pre, m.match(0), m.post);

Or even more concisely as:

if (auto m = std.regexp.search("abcdef", "c"))
    writefln("%s[%s]%s", m.pre, m.match(0), m.post); // writes ab[c]def

Search and Replace

Search and replace gets more interesting. To replace the occurrences of "a" with "ZZ" in Ruby; the first occurrence, then all:

s = "Strap a rocket engine on a chicken."
s.sub(/a/, "ZZ") // result: StrZZp a rocket engine on a chicken.
s.gsub(/a/, "ZZ") // result: StrZZp ZZ rocket engine on ZZ chicken.

In D:

s = "Strap a rocket engine on a chicken.";
sub(s, "a", "ZZ");        // result: StrZZp a rocket engine on a chicken.
sub(s, "a", "ZZ", "g");   // result: StrZZp ZZ rocket engine on ZZ chicken.

The replacement string can reference the matches using the $&, $$, $', $`, .. 9 notation:

sub(s, "[ar]", "[$&]", "g"); // result: St[r][a]p [a] [r]ocket engine on [a] chicken.

Or the replacement string can be provided by a delegate:

sub(s, "[ar]",
   (RegExp m) { return toupper(m.match(0)); },
   "g");    // result: StRAp A Rocket engine on A chicken.
(toupper() comes from std.string.)

Looping

It's possible to search over all matches within a string:

import std.stdio;
import std.regexp;

void main()
{
    foreach(m; RegExp("ab").search("abcabcabab"))
    {
        writefln("%s[%s]%s", m.pre, m.match(0), m.post);
    }
}
// Prints:
// [ab]cabcabab
// abc[ab]cabab
// abcabc[ab]ab
// abcabcab[ab]

Conclusion

D regular expression handling is as powerful as Ruby's. But its syntax isn't as concise:

  • Regular expression literal syntax - doing so would make it impossible to perform lexical analysis without also doing syntactic or semantic analysis.
  • Implicit naming of match variables - this causes problems with name collisions, and just doesn't fit with the rest of the way D works.

But it is just as powerful.


LazyEvaluationOfFunctionArguments

Last update Sun Dec 30 20:34:43 2012

Lazy Evaluation of Function Arguments

by Walter Bright, http://www.digitalmars.com/d

Lazy evaluation is the technique of not evaluating an expression unless and until the result of the expression is required. The &&, || and ?: operators are the conventional way to do lazy evaluation:

void test(int* p)
{
    if (p && p[0])
    ...
}

The second expression p[0] is not evaluated unless p is not null. If the second expression was not lazily evaluated, it would generate a runtime fault if p was null.

While invaluable, the lazy evaluation operators have significant limitations. Consider a logging function, which logs a message, and can be turned on and off at runtime based on a global value:

void log(char[] message)
{
    if (logging)
    fwritefln(logfile, message);
}

Often, the message string will be constructed at runtime:

void foo(int i)
{
    log("Entering foo() with i set to " ~ toString(i));
}

While this works, the problem is that the building of the message string happens regardless of whether logging is enabled or not. With applications that make heavy use of logging, this can become a terrible drain on performance.

One way to fix it is by using lazy evaluation:

void foo(int i)
{
    if (logging) log("Entering foo() with i set to " ~ toString(i));
}

but this violates encapsulation principles by exposing the details of logging to the user. In C, this problem is often worked around by using a macro:

#define LOG(string)  (logging && log(string))

but that just papers over the problem. Preprocessor macros have well known shortcomings:

  • The logging variable is exposed in the user's namespace.
  • Macros are invisible to symbolic debuggers.
  • Macros are global only, and cannot be scoped.
  • Macros cannot be class members.
  • Macros cannot have their address taken, so cannot be passed indirectly like functions can.

A robust solution would be a way to do lazy evaluation of function parameters. Such a way is possible in the D programming language using a delegate parameter:

void log(char[] delegate() dg)
{
    if (logging)
    fwritefln(logfile, dg());
}

void foo(int i)
{
    log( { return "Entering foo() with i set to " ~ toString(i); });
}

Now, the string building expression only gets evaluated if logging is true, and encapsulation is maintained. The only trouble is that few are going to want to wrap expressions with { return exp; }.

So D takes it one small, but crucial, step further (suggested by Andrei Alexandrescu). Any expression can be implicitly converted to a delegate that returns either void or the type of the expression. The delegate declaration is replaced by the lazy storage class (suggested by Tomasz Stachowiak). The functions then become:

void log(lazy char[] dg)
{
    if (logging)
    fwritefln(logfile, dg());
}

void foo(int i)
{
    log("Entering foo() with i set to " ~ toString(i));
}

which is our original version, except that now the string is not constructed unless logging is turned on.

Any time there is a repeating pattern seen in code, being able to abstract out that pattern and encapsulate it means we can reduce the complexity of the code, and hence bugs. The most common example of this is the function itself. Lazy evaluation enables encapsulation of a host of other patterns.

For a simple example, suppose an expression is to be evaluated count times. The pattern is:

for (int i = 0; i < count; i++)
   exp;

This pattern can be encapsulated in a function using lazy evaluation:

void dotimes(int count, lazy void exp)
{
    for (int i = 0; i < count; i++)
       exp();
}

It can be used like:

void foo()
{
    int x = 0;
    dotimes(10, writef(x++));
}

which will print:

0123456789

More complex user defined control structures are possible. Here's a method to create a switch like structure:

bool scase(bool b, lazy void dg)
{
    if (b)
    dg();
    return b;
}

/* Here the variadic arguments are converted to delegates in this
   special case.
 */
void cond(bool delegate()[] cases ...)
{
    foreach (c; cases)
    {	if (c())
        break;
    }
}

which can be used like:

void foo()
{
    int v = 2;
    cond
    (
    scase(v == 1, writefln("it is 1")),
    scase(v == 2, writefln("it is 2")),
    scase(v == 3, writefln("it is 3")),
    scase(true,   writefln("it is the default"))
    );
}

which will print:

it is 2

Those familiar with the Lisp programming language will notice some intriguing parallels with Lisp macros.

For a last example, there is the common pattern:

Abc p;
p = foo();
if (!p)
    throw new Exception("foo() failed");
p.bar();	// now use p

Because throw is a statement, not an expression, expressions that need to do this need to be broken up into multiple statements, and extra variables are introduced. (For a thorough treatment of this issue, see Andrei Alexandrescu and Petru Marginean's paper Enforcements). With lazy evaluation, this can all be encapsulated into a single function:

Abc Enforce(Abc p, lazy char[] msg)
{
    if (!p)
    throw new Exception(msg());
    return p;
}

and the opening example above becomes simply:

Enforce(foo(), "foo() failed").bar();

and 5 lines of code become one. Enforce can be improved by making it a template function:

T Enforce(T)(T p,  lazy char[] msg)
{
    if (!p)
    throw new Exception(msg());
    return p;
}

Conclusion

Lazy evaluation of function arguments dramatically extends the expressive power of functions. It enables the encapsulation into functions of many common coding patterns and idioms that previously were too clumsy or impractical to do.

Acknowledgements

I gratefully acknowledge the inspiration and assistance of Andrei Alexandrescu, Bartosz Milewski, and David Held. The D community helped a lot with much constructive criticism, such as the thread starting with Tomasz Stachowiak in D/41633 .


Variadic Templates

Last update Sun Dec 30 20:34:43 2012

Variadic Templates

The problem statement is simple: write a function that takes an arbitrary number of values of arbitrary types, and print those values out one per line in a manner appropriate to the type. For example, the code:

print(7, 'a', 6.8);

should output:

7
'a'
6.8

We'll explore how this can be done in standard C++, followed by doing it using the proposed variadic template C++ extension. Then, we'll do it the various ways the D programming language makes possible.

C++ Solutions

The Standard C++ Solution

The straightforward way to do this in standard C++ is to use a series of function templates, one for each number of arguments:

#include <iostream>
using namespace::std;

void print()
{
}

template<class T1> void print(T1 a1)
{
    cout << a1 << endl;
}

template<class T1, class T2> void print(T1 a1, T2 a2)
{
    cout << a1 << endl;
    cout << a2 << endl;
}

template<class T1, class T2, class T3> void print(T1 a1, T2 a2, T3 a3)
{
    cout << a1 << endl;
    cout << a2 << endl;
    cout << a3 << endl;
}

... etc ...

This poses significant problems:

One, the function implementor must decide in advance what the maximum number of arguments the function will have. The implementor will usually err on the side of excess, and ten, or even twenty overloads of print() will be written. Yet inevitably, some user somewhere will require just one more argument. So this solution is never quite thoroughly right.

Two, the logic of the function template body must be cut and paste duplicated, then carefully modified, for every one of those function templates. If the logic needs to be adjusted, all of those function templates must receive the same adjustment, which is tedious and error prone.

Three, as is typical for function overloads, there is no obvious visual connection between them, they stand independently. This makes it more difficult to understand the code, especially if the implementor isn't careful to place them and format them in a consistent style.

Four, it leads to source code bloat which slows down compilation.

The C++ Extension Solution

Douglas Gregor has proposed a variadic template scheme [1] for C++ that solves these problems. The result looks like:

void print()
{
}

template<class T, class... U> void print(T a1, U... an)
{
    cout << a1 << newline;
    print(an...);
}

It uses recursive function template instantiation to pick off the arguments one by one. A specialization with no arguments ends the recursion. It's a neat and tidy solution, but with one glaring problem: it's a proposed extension, which means it isn't part of the C++ standard, may not get into the C++ standard in its current form, may not get into the standard in any form, and even if it does, it may be many, many years before the feature is commonly implemented.

D Programming Language Solutions

The D Look Ma No Templates Solution

It is not practical to solve this problem in C++ without using templates. In D, one can because D supports typesafe variadic function parameters.

import std.stdio;

void print(...)
{
    foreach (arg; _arguments)
    {
    writefx(stdout, (&arg)[0 .. 1], _argptr, 1);
    auto size = arg.tsize();
    _argptr += ((size + size_t.sizeof - 1) & ~(size_t.sizeof - 1));
    }
}

It isn't elegant or the most efficient, but it does work, and it is neatly encapsulated into a single function. (It relies on the predefined parameters _argptr and _arguments which give a pointer to the values and their types, respectively.)

Translating the Variadic C++ Solution into D

Variadic templates in D enable a straightforward translation of the proposed C++ variadic syntax:

void print()()
{
}

void print(T, A...)(T t, A a)
{
    writefln(t);
    print(a);
}

There are two function templates. The first provides the degenerate case of no arguments, and a terminus for the recursion of the second. The second has two arguments: t for the first value and a for the rest of the values. A... says the parameter is a tuple, and implicit function template instantiation will fill in A with the list of all the types following t. So, print(7, 'a', 6.8) will fill in int for T, and a tuple (char, double) for A. The parameter a becomes an expression tuple of the arguments.

The function works by printing the first parameter t, and then recursively calling itself with the remaining arguments a. The recursion terminates when there are no longer any arguments by calling print()().

The Static If Solution

It would be nice to encapsulate all the logic into a single function. One way to do that is by using static if's, which provide for conditional compilation:

void print(A...)(A a)
{
    static if (a.length)
    {
    writefln(a[0]);
    static if (a.length > 1)
        print(a[1 .. length]);
    }
}

Tuples can be manipulated much like arrays. So a.length resolves to the number of expressions in the tuple a. a[0] gives the first expression in the tuple. a[1 .. length] creates a new tuple by slicing the original tuple.

The Foreach Solution

But since tuples can be manipulated like arrays, we can use a foreach statement to 'loop' over the tuple's expressions:

void print(A...)(A a)
{
    foreach(t; a)
    writefln(t);
}

The end result is remarkably simple, self-contained, compact and efficient.

Acknowledgments

  1. Thanks to Andrei Alexandrescu for explaining to me how variadic templates need to work and why they are so important.
  2. Thanks to Douglas Gregor, Jaakko Jaervi, and Gary Powell for their inspirational work on C++ variadic templates.

References

  1. Variadic Templates N2080


Tuples

Last update Sun Dec 30 20:34:43 2012

Tuples

A tuple is a sequence of elements. Those elements can be types, expressions, or aliases. The number and elements of a tuple are fixed at compile time; they cannot be changed at run time.

Tuples have characteristics of both structs and arrays. Like structs, the tuple elements can be of different types. Like arrays, the elements can be accessed via indexing.

So how does one construct a tuple? There isn't a specific tuple literal syntax. But since variadic template parameters create tuples, we can define a template to create one:

template Tuple(E...)
{
    alias E Tuple;
}

and it's used like:

Tuple!(int, long, float)	// create a tuple of 3 types
Tuple!(3, 7, 'c')		// create a tuple of 3 expressions
Tuple!(int, 8)			// create a tuple of a type and an expression

In order to symbolically refer to a tuple, use an alias:

alias Tuple!(float, float, 3) TP; // TP is now a tuple of two floats and 3

Tuples can be used as arguments to templates, and if so they are 'flattened' out into a list of arguments. This makes it straightforward to append a new element to an existing tuple or concatenate tuples:

alias Tuple!(TP, 8) TR;  // TR is now float,float,3,8
alias Tuple!(TP, TP) TS; // TS is float,float,3,float,float,3

Tuples share many characteristics with arrays. For starters, the number of elements in a tuple can be retrieved with the .length property:

TP.length	// evaluates to 3

Tuples can be indexed:

TP[1] f = TP[2];	// f is declared as a float and initialized to 3

and even sliced:

alias TP[0..length-1] TQ; // TQ is now the same as Tuple!(float, float)

Yes, length is defined within the [ ]s. There is one restriction: the indices for indexing and slicing must be evaluatable at compile time.

void foo(int i)
{
    TQ[i] x;		// error, i is not constant
}

These make it simple to produce the 'head' and 'tail' of a tuple. The head is just TP[0], the tail is TP[1 .. length]. Given the head and tail, mix with a little conditional compilation, and we can implement some classic recursive algorithms with templates. For example, this template returns a tuple consisting of the trailing type arguments TL with the first occurrence of the first type argument T removed:

template Erase(T, TL...)
{
    static if (TL.length == 0)
    // 0 length tuple, return self
        alias TL Erase;
    else static if (is(T == TL[0]))
    // match with first in tuple, return tail
        alias TL[1 .. length] Erase;
    else
    // no match, return head concatenated with recursive tail operation
        alias Tuple!(TL[0], Erase!(T, TL[1 .. length])) Erase;
}

Type Tuples

If a tuple's elements are solely types, it is called a TypeTuple (sometimes called a type list). Since function parameter lists are a list of types, a type tuple can be retrieved from them. One way is using an IsExpression:

int foo(int x, long y);

...
static if (is(foo P == function))
    alias P TP;
// TP is now the same as Tuple!(int, long)

This is generalized in the template std.traits.ParameterTypeTuple:

import std.traits;

...
alias ParameterTypeTuple!(foo) TP;	// TP is the tuple (int, long)

TypeTuples can be used to declare a function:

float bar(TP);	// same as float bar(int, long)

If implicit function template instantiation is being done, the type tuple representing the parameter types can be deduced:

int foo(int x, long y);

void Bar(R, P...)(R function(P))
{
    writefln("return type is ", typeid(R));
    writefln("parameter types are ", typeid(P));
}

...
Bar(&foo);

Prints:

return type is int
parameter types are (int,long)

Type deduction can be used to create a function that takes an arbitrary number and type of arguments:

void Abc(P...)(P p)
{
    writefln("parameter types are ", typeid(P));
}

Abc(3, 7L, 6.8);

Prints:

parameter types are (int,long,double)

For a more comprehensive treatment of this aspect, see Variadic Templates.

Expression Tuples

If a tuple's elements are solely expressions, it is called an ExpressionTuple. The Tuple template can be used to create one:

alias Tuple!(3, 7L, 6.8) ET;

...
writefln(ET);            // prints 376.8
writefln(ET[1]);         // prints 7
writefln(ET[1..length]); // prints 76.8

It can be used to create an array literal:

alias Tuple!(3, 7, 6) AT;

...
int[] a = [AT];		// same as [3,7,6]

The data fields of a struct or class can be turned into an expression tuple using the .tupleof property:

struct S { int x; long y; }

void foo(int a, long b)
{
    writefln(a, b);
}

...
S s;
s.x = 7;
s.y = 8;
foo(s.x, s.y);	// prints 78
foo(s.tupleof);	// prints 78
s.tupleof[1] = 9;
s.tupleof[0] = 10;
foo(s.tupleof); // prints 109
s.tupleof[2] = 11;  // error, no third field of S

A type tuple can be created from the data fields of a struct using typeof:

writefln(typeid(typeof(S.tupleof)));	// prints (int,long)

This is encapsulated in the template std.traits.FieldTypeTuple.

Looping

While the head-tail style of functional programming works with tuples, it's often more convenient to use a loop. The ForeachStatement can loop over either TypeTuples or ExpressionTuples.

alias Tuple!(int, long, float) TL;
foreach (i, T; TL)
    writefln("TL[%d] = ", i, typeid(T));

alias Tuple!(3, 7L, 6.8) ET;
foreach (i, E; ET)
    writefln("ET[%d] = ", i, E);

Prints:

TL[0] = int
TL[1] = long
TL[2] = float
ET[0] = 3
ET[1] = 7
ET[2] = 6.8

Tuple Declarations

A variable declared with a TypeTuple becomes an ExpressionTuple:

alias Tuple!(int, long) TL;

void foo(TL tl)
{
    writefln(tl, tl[1]);
}

foo(1, 6L);	// prints 166

Putting It All Together

These capabilities can be put together to implement a template that will encapsulate all the arguments to a function, and return a delegate that will call the function with those arguments.

import std.stdio;

R delegate() CurryAll(Dummy=void, R, U...)(R function(U) dg, U args)
{
    struct Foo
    {
    typeof(dg) dg_m;
    U args_m;

    R bar()
    {
        return dg_m(args_m);
    }
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    foreach (i, arg; args)
    f.args_m[i] = arg;
    return &f.bar;
}

R delegate() CurryAll(R, U...)(R delegate(U) dg, U args)
{
    struct Foo
    {
    typeof(dg) dg_m;
    U args_m;

    R bar()
    {
        return dg_m(args_m);
    }
    }

    Foo* f = new Foo;
    f.dg_m = dg;
    foreach (i, arg; args)
    f.args_m[i] = arg;
    return &f.bar;
}

void main()
{
    static int plus(int x, int y, int z)
    {
    return x + y + z;
    }

    auto plus_two = CurryAll(&plus, 2, 3, 4);
    writefln("%d", plus_two());
    assert(plus_two() == 9);

    int minus(int x, int y, int z)
    {
    return x + y + z;
    }

    auto minus_two = CurryAll(&minus, 7, 8, 9);
    writefln("%d", minus_two());
    assert(minus_two() == 24);
}

The reason for the Dummy parameter is that one cannot overload two templates with the same parameter list. So we make them different by giving one a dummy parameter.

Future Directions

  • Return tuples from functions.
  • Use operators on tuples, like =, +=, etc.
  • Have tuple properties like .init which will apply the property to each of the tuple members.


Mixins

Last update Sun Dec 30 20:34:42 2012

Mixins

Mixins (not to be confused with template mixins) enable string constants to be compiled as regular D code and inserted into the program. Combining this with compile time manipulation of strings enables the creation of domain-specific languages.

For example, here we can create a template that generates a struct with the named members:

template GenStruct(char[] Name, char[] M1)
{
    const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}

mixin(GenStruct!("Foo", "bar"));

which generates:

struct Foo { int bar; }

Superficially, since D mixins can manipulate text and compile the result, it has some similar properties to the C preprocessor. But there are major, fundamental differences:

  • The C preprocessing step occurs before lexical analysis. This makes it impossible to lex or parse C without access to all of the context, including all #include'd files, paths and all relevant compiler switches. Mixins occur during semantic analysis, and do not affect the lexing or parsing process. Lexing and parsing can still occur without semantic analysis.
  • The C preprocessor can be used to create what appears to be different syntax:
    #define BEGIN {
#define END   }

BEGIN
  int x = 3;
  foo(x);
END
    This monkey business is impossible with mixins. Mixed in text must form complete declarations, statements, or expressions.
  • C macros will affect everything following that has the same name, even if they are in nested scopes. C macros cut across all scopes. This problem is called being not "coding hygenic". Mixins follow the usual scoping rules, and is hygenic.
  • C preprocessing expressions follow a different syntax and have different semantic rules than the C language. The C preprocessor is technically a different language. Mixins are in the same language.
  • C const declarations and C++ templates are invisible to C preprocessing. Mixins can be manipulated using templates and const declarations.


DMD Compiler for Linux

Last update Sun Dec 30 20:34:44 2012

dmd - Linux D Compiler

  • dmd for Windows
  • dmd for OSX
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 and 64 bit x86-64 Linux operating system
  3. Gnu C compiler (gcc)

Files

/dmd/src/phobos/
D runtime library source
/dmd/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
/dmd/html/d/
Documentation
/dmd/samples/d/
Sample D programs
/dmd/linux/bin/dmd
D compiler executable
/dmd/linux/bin/dumpobj
Elf file dumper
/dmd/linux/bin/obj2asm
Elf file disassembler
/dmd/linux/bin/shell
Simple command line shell
/dmd/linux/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
/dmd/linux/lib/libphobos.a
D runtime library (copy to /usr/lib/libphobos.a)

Installation

  • Unzip the archive into your home directory. It will create a ~/dmd directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Copy dmd.conf to /etc:
    cp /dmd/linux/bin/dmd.conf /etc
  • Put /dmd/linux/bin on your PATH, or copy the linux executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp /dmd/linux/lib/libphobos.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries).
    -g
    add Dwarf symbolic debug info with D extensions for debuggers such as ZeroBUGS
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -map
    generate a .map file
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts, asserts and array bounds checking
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]
DFLAGS=-I%@P%/../src/phobos

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~//dmd/src/dmd
make -f .mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~//dmd/src/phobos
make -f .mak DMD=~//dmd//bin/dmd


DMD Compiler for FreeBSD

Last update Sun Dec 30 20:34:44 2012

dmd - FreeBSD D Compiler

  • dmd for Windows
  • dmd for Linux
  • dmd for OSX
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 FreeBSD 7.1 operating system
  3. Gnu C compiler (gcc)

Files

/dmd/src/phobos/
D runtime library source
/dmd/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
/dmd/html/d/
Documentation
/dmd/samples/d/
Sample D programs
/dmd/freebsd/bin/dmd
D compiler executable
/dmd/freebsd/bin/dumpobj
Elf file dumper
/dmd/freebsd/bin/obj2asm
Elf file disassembler
/dmd/freebsd/bin/shell
Simple command line shell
/dmd/freebsd/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
/dmd/freebsd/lib/libphobos.a
D runtime library (copy to /usr/lib/libphobos.a)

Installation

  • Unzip the archive into your home directory. It will create a ~/dmd directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Copy dmd.conf to /etc:
    cp /dmd/freebsd/bin/dmd.conf /etc
  • Put /dmd/freebsd/bin on your PATH, or copy the FreeBSD executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp /dmd/freebsd/lib/libphobos.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries).
    -g
    add Dwarf symbolic debug info with D extensions for debuggers
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -map
    generate a .map file
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts, asserts and array bounds checking
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]
DFLAGS=-I%@P%/../src/phobos

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~//dmd/src/dmd
make -f .mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~//dmd/src/phobos
make -f .mak DMD=~//dmd//bin/dmd


DMD Compiler for OSX

Last update Sun Dec 30 20:34:44 2012

dmd - Mac OS X D Compiler

  • dmd for Windows
  • dmd for Linux
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • dmd.conf Initialization File
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit x86 Mac OSX operating system
  3. Gnu C compiler (gcc)

Files

/dmd/src/phobos/
D runtime library source
/dmd/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
/dmd/html/d/
Documentation
/dmd/samples/d/
Sample D programs
/dmd/osx/bin/dmd
D compiler executable
/dmd/osx/bin/dumpobj
Mach-O file dumper
/dmd/osx/bin/obj2asm
Mach-O file disassembler
/dmd/osx/bin/shell
Simple command line shell
/dmd/osx/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
/dmd/osx/lib/libphobos.a
D runtime library (copy to /usr/lib/libphobos.a)

Installation

  • Put the dmd zip file into your home directory, and unzip it:
    unzip dmd.VERSION.zip
    where VERSION is the particular version of the zip file.
  • It will create a ~//dmd directory with all the files in it. All the tools are command line tools, which means they are run from a console window.
  • Verify that this works by creating hello.d in your home directory with these contents:
    import std.stdio;

void main() {
    writeln("hello world!");
}
    and compile and run it with:
    /dmd/osx/bin/dmd hello
./hello
    and it should print:
    hello world!
  • To install a global copy:
  • Copy binaries to /usr/local/bin:
    sudo cp /dmd/osx/bin/{dmd,dumpobj,obj2asm,shell} /usr/local/bin
sudo cp /dmd/osx/bin/dmdx.conf /usr/local/bin/dmd.conf
  • Copy the library to /usr/lib:
    sudo cp /dmd/osx/lib/libphobos.a /usr/lib

    • Compiler Arguments and Switches

    dmd files... -switches...
    files...
    File Extensions
    Extension | File Type
    none | D source files
    .d | D source files
    .dd | Ddoc source files
    .di | D interface files
    .o | Object files to link in
    .a | Object code libraries to search
    @cmdfile
    If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile
    -c
    compile only, do not link
    -cov
    instrument for code coverage analysis
    -D
    generate documentation from source
    -Dd docdir
    write documentation file to docdir directory
    -Df filename
    write documentation file to filename
    -d
    allow deprecated features
    -debug
    compile in debug code
    -debug=level
    compile in debug level <= level
    -debug=ident
    compile in debug identifier ident
    -debuglib=libname
    link in libname as the default library when compiling for symbolic debugging instead of libphobos.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos.a
    -deps=filename
    write module dependencies as text to filename
    -fPIC
    generate Position Independent Code (which is used for building shared libraries). This is always on for OSX.
    -g
    add Dwarf symbolic debug info with D extensions for debuggers
    -gc
    add Dwarf symbolic debug info in C format for debuggers such as gdb
    -gs
    always generate standard stack frame
    -H
    generate D interface file
    -Hd dir
    write D interface file to dir directory
    -Hf filename
    write D interface file to filename
    --help
    print brief help to console
    -I path
    where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
    -ignore
    ignore unsupported pragmas
    -inline
    inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
    -J path
    where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
    -L linkerflag
    pass linkerflag to the linker, for example, -L-M
    -lib
    generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
    -m32
    compile a 32 bit executable. This is the default for the 32 bit dmd.
    -m64
    compile a 64 bit executable. This is the default for the 64 bit dmd.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, Safari is assumed.
    -map
    generate a .map file
    -O
    Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
    -o-
    Suppress generation of object file. Useful in conjuction with -D or -H flags.
    -od objdir
    write object files relative to directory objdir instead of to the current directory
    -of filename
    Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
    -op
    normally the path for .d source files is stripped off when generating an object file name. -op will leave it on.
    -profile
    profile the runtime performance of the generated code
    -quiet
    suppress non-essential compiler messages
    -release
    compile release version, which means not generating code for contracts, asserts and array bounds checking
    -run srcfile args... compile
    link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .o or executable file is left behind.
    -shared
    generate shared library
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -version=level
    compile in version level >= level
    -version=ident
    compile in version identifier ident
    -w
    enable warnings
    -wi
    enable informational warnings (i.e. compilation still proceeds normally)
    -X
    generate JSON file
    -Xf filename
    write JSON file to filename

    Linking

    Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

    The actual linking is done by running gcc. This ensures compatibility with modules compiled with gcc.

    Environment Variables

    The D compiler dmd uses the following environment variables:

    CC
    dmd normally runs the linker by looking for gcc along the PATH. To use a specific linker instead, set the CC environment variable to it. For example:
    set CC=gcc
    BROWSER
    This sets the browser used to open the manual page with the -man switch. It defaults to x-www-browser.
    DFLAGS
    The value of DFLAGS is treated as if it were appended to the command line to dmd.

    dmd.conf Initialization File

    The dmd file dmd.conf is the same as sc.ini for Windows, it's just that the file has a different name, enabling a setup common to both Windows and this system to be created without having to re-edit the file.

    dmd will look for the initialization file dmd.conf in the following sequence of directories:

    1. current working directory
    2. directory specified by the HOME environment variable
    3. directory dmd resides in
    4. /etc/

    If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

    Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

    ; dmd.conf file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]
DFLAGS=-I%@P%/../src/phobos

    Differences between Windows and Linux versions

    • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

    D Interface Files

    When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

    The advantages of using a D interface file for imports rather than a D source file are:

    • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
    • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

    D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

    D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

    Building Executables

    dmd can build an executable much faster if as many of the source files as possible are put on the command line.

    Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

    Building Libraries

    There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.o and existing library def.a which are all to be combined into a library foo.a:

    1. Compile modules separately and then run the librarian on them:
      dmd -c foo.d
dmd -c bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
      This option is typical when using a makefile to avoid compiling modules that have already been compiled.
    2. Compile modules together and then run the librarian on them:
      dmd -c foo.d bar.d
rm -f foo.a
ar -r foo.a foo.o bar.o abc.o def.a
rm foo.o bar.o
    3. Use dmd to compile and build library in one operation:
      dmd -lib foo.d bar.d abc.o def.a
      No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

    Compiling dmd

    Complete source code is provided to build the compiler. Follow these steps:

    cd ~//dmd/src/dmd
make -f .mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~//dmd/src/phobos
make -f .mak DMD=~//dmd//bin/dmd


DMD Compiler for Windows

Last update Sun Dec 30 20:34:44 2012

dmd - Windows D Compiler

  • dmd for Linux
  • dmd for OSX
  • dmd for FreeBSD
  • Requirements and Downloads
  • Files
  • Installation
  • Example
  • Compiler Arguments and Switches
  • Linking
  • Environment Variables
  • sc.ini Initialization File
  • Common Installation Problems
  • Differences between Windows and Linux versions
  • D Interface Files
  • Building Libraries
  • Compiling dmd
  • Compiling Phobos

Requirements and Downloads

  1. Download D Compiler
  2. 32 bit Windows (Win32) operating system, such as Windows XP
  3. Download dmc.zip (C and C++ compiler) for Win32 (not required, but it complements dmd for Windows)

Files

\dmd\src\phobos\
D runtime library source
\dmd\src\dmd\
D compiler front end source under dual (GPL and Artistic) license
\dmd\html\d\
Documentation
\dmd\samples\d\
Sample D programs
\dmd\windows\bin\dmd.exe
D compiler executable
\dmd\windows\bin\shell.exe
Simple command line shell
\dmd\windows\bin\sc.ini
Global compiler settings
\dmd\windows\lib\phobos.lib
D runtime library

Installation

Open a console window (for Windows XP this is done by clicking on [Start][Command Prompt]). All the tools are command line tools, which means they are run from a console window. Switch to the root directory. Unzip the files in the root directory. dmd.zip will create a \dmd directory with all the files in it. dmc.zip will create a \dm directory with all the files in it.

A typical session might look like:

C:\Documents and Settings\Your Name>cd \
C:\>unzip dmd.zip
C:\>unzip dmc.zip

Example

Run:

\dmd\\bin\shell all.sh

in the \dmd\samples\d directory for several small examples.

Compiler Arguments and Switches

dmd files... -switches...
files...
File Extensions
Extension | File Type
none | D source files
.d | D source files
.dd | Ddoc source files
.di | D interface files
.obj | Object files to link in
.lib | Object code libraries to search
.exe | Output executable file
.def | module definition file
.res | resource file
@cmdfile
If cmdfile is an environment variable, read the compiler arguments and switches from the value of that variable. Otherwise, read compiler arguments and switches from the text file cmdfile
-c
compile only, do not link
-cov
instrument for code coverage analysis
-D
generate documentation from source
-Dd docdir
write documentation file to docdir directory
-Df filename
write documentation file to filename
-d
allow deprecated features
-debug
compile in debug code
-debug=level
compile in debug level <= level
-debug=ident
compile in debug identifier ident
-debuglib=libname
link in libname as the default library when compiling for symbolic debugging instead of phobos.lib
-defaultlib=libname
link in libname as the default library when not compiling for symbolic debugging instead of phobos.lib
-deps=filename
write module dependencies as text to filename
-g
add CodeView 4 symbolic debug info with D extensions for debuggers such as Ddbg
-gc
add CodeView 4 symbolic debug info in C format for debuggers such as \dmd\bin\windbg
-gs
always generate standard stack frame
-H
generate D interface file
-Hd dir
write D interface file to dir directory
-Hf filename
write D interface file to filename
--help
print brief help to console
-I path
where to look for imports. path is a ; separated list of paths. Multiple -I's can be used, and the paths are searched in the same order.
-ignore
ignore unsupported pragmas
-inline
inline expand functions at the discretion of the compiler. This can improve performance, at the expense of making it more difficult to use a debugger on it.
-J path
where to look for files for ImportExpressions. This switch is required in order to use ImportExpressions. path is a ; separated list of paths. Multiple -J's can be used, and the paths are searched in the same order.
-L linkerflag
pass linkerflag to the linker , for example, -L/ma/li
-lib
generate library file as output instead of object file(s). All compiled source files, as well as object files and library files specified on the command line, are inserted into the output library. Compiled source modules may be partitioned into several object modules to improve granularity. The name of the library is taken from the name of the first source module to be compiled. This can be overridden with the -of switch.
-man
open default browser on this page
-map
generate a .map file
-nofloat
Prevents emission of __fltused reference in object files, even if floating point code is present. Useful for library code.
-O
Optimize generated code. For fastest executables, compile with the -O -release -inline switches together.
-o-
Suppress generation of object file. Useful in conjuction with -D or -H flags.
-od objdir
write object files relative to directory objdir instead of to the current directory
-of filename
Set output file name to filename in the output directory. The output file can be an object file, executable file, or library file depending on the other switches.
-op
normally the path for .d source files is stripped off when generating an object file name. -op will leave it on.
-profile
profile the runtime performance of the generated code
-quiet
suppress non-essential compiler messages
-release
compile release version, which means not generating code for contracts, asserts and array bounds checking
-run srcfile args... compile
link, and run the program srcfile with the rest of the command line, args..., as the arguments to the program. No .obj or executable file is left behind.
-unittest
compile in unittest code, turns on asserts, and sets the unittest version identifier
-v
verbose
-version=level
compile in version level >= level
-version=ident
compile in version identifier ident
-w
enable warnings
-wi
enable informational warnings (i.e. compilation still proceeds normally)
-X
generate JSON file
-Xf filename
write JSON file to filename

Empty switches, i.e. "", are ignored.

Linking

Linking is done directly by the dmd compiler after a successful compile. To prevent dmd from running the linker, use the -c switch.

The programs must be linked with the D runtime library phobos.lib, followed by the C runtime library snn.lib. This is done automatically as long as the directories for the libraries are on the LIB environment variable path. A typical way to set LIB would be:

set LIB=\dmd\lib;\dm\lib

If the dmd command is used to both compile and link to an executable, it will make certain optimizations that are valid only for Windows executable files. Do not use the resulting .obj files in a DLL. To compile modules into .obj files that can be used in an exe or DLL, compile with -c.

Linking is done using the optlink linker.

Environment Variables

The D compiler dmd uses the following environment variables:

DFLAGS
The value of DFLAGS is treated as if it were appended to the command line to dmd.exe.
LIB
The linker uses LIB to search for library files. For D, it will normally be set to:
set LIB=\dmd\lib;\dm\lib
LINKCMD
dmd normally runs the linker by looking for link.exe along the PATH. To use a specific linker instead, set the LINKCMD environment variable to it. For example:
set LINKCMD=\dmd\windows\bin\link
PATH
If the linker is not found in the same directory as dmd.exe is in, the PATH is searched for it. Note: other linkers named link.exe will likely not work. Make sure the Digital Mars link.exe is found first in the PATH before other link.exe's, or use LINKCMD to specifically identify which linker to use.

sc.ini Initialization File

dmd will look for the initialization file sc.ini in the following sequence of directories:

  1. current working directory
  2. directory specified by the HOME environment variable
  3. directory dmd.exe resides in

If found, environment variable settings in the file will override any existing settings. This is handy to make dmd independent of programs with conflicting use of environment variables.

Initialization File Format

Comments are lines that begin with ; and are ignored.

Environment variables follow the [Environment] section heading, in NAME=value pairs. The NAMEs are treated as upper case. Comments are lines that start with ;. For example:

; sc.ini file for dmd
; Names enclosed by %% are searched for in the existing environment
; and inserted. The special name %@P% is replaced with the path
; to this file.
[Environment]
LIB="%@P%\..\lib";\dm\lib
DFLAGS="-I%@P%\..\src\phobos"

LINKCMD="%@P%\..\..\dm\bin"
DDOCFILE=mysettings.ddoc

Location Independence of sc.ini

The %@P% is replaced with the path to sc.ini. Thus, if the fully qualified file name sc.ini is c:\dmd\bin\sc.ini, then %@P% will be replaced with c:\dmd\bin, and the above sc.ini will be interpreted as:

[Environment]
LIB="c:\dmd\bin\..\lib";\dm\lib
DFLAGS="-Ic:\dmd\bin\..\src\phobos"

LINKCMD="c:\dmd\bin\..\..\dm\bin"
DDOCFILE=mysettings.ddoc

This enables your dmd setup to be moved around without having to re-edit sc.ini.

Common Installation Problems

  • Using Cygwin's unzip utility has been known to cause strange problems.
  • Running the compiler under Cygwin's command shell has been also known to cause problems. Try getting it to work under the regular Windows shell cmd.exe before trying Cygwin's.
  • Installing dmd and dmc into directory paths with spaces in them causes problems.

Differences between Windows and Linux versions

  • String literals are read-only under Linux. Attempting to write to them will cause a segment violation.

D Interface Files

When an import declaration is processed in a D source file, the compiler searches for the D source file corresponding to the import, and processes that source file to extract the information needed from it. Alternatively, the compiler can instead look for a corresponding D interface file. A D interface file contains only what an import of the module needs, rather than the whole implementation of that module.

The advantages of using a D interface file for imports rather than a D source file are:

  • D interface files are often significantly smaller and much faster to process than the corresponding D source file.
  • They can be used to hide the source code, for example, one can ship an object code library along with D interface files rather than the complete source code.

D interface files can be created by the compiler from a D source file by using the -H switch to the compiler. D interface files have the .di file extension. When the compiler resolves an import declaration, it first looks for a .di D interface file, then it looks for a D source file.

D interface files bear some analogous similarities to C++ header files. But they are not required in the way that C++ header files are, and they are not part of the D language. They are a feature of the compiler, and serve only as an optimization of the build process.

Building Executables

dmd can build an executable much faster if as many of the source files as possible are put on the command line.

Another advantage to putting multiple source files on the same invocation of dmd is that dmd will be able to do some level of cross-module optimizations, such as function inlining across modules.

Building Libraries

There are three ways to build a library. For example, given foo.d and bar.d which are to be compiled, and existing object file bar.obj and existing library def.lib which are all to be combined into a library foo.lib:

  1. Compile modules separately and then run the librarian on them:
    dmd -c foo.d
dmd -c bar.d
lib -c -p32 foo.lib foo.obj bar.obj abc.obj def.lib
del foo.obj bar.obj
    This option is typical when using a makefile to avoid compiling modules that have already been compiled.
  2. Compile modules together and then run the librarian on them:
    dmd -c foo.d bar.d
lib -c -p32 foo.lib foo.obj bar.obj abc.obj def.lib
del foo.obj bar.obj
  3. Use dmd to compile and build library in one operation:
    dmd -lib foo.d bar.d abc.obj def.lib
    No object files are written to disk, it's all done in memory. Using -lib also has the advantage that modules may be compiled into multiple object files rather than exactly one per module. This improves granularity of the library without having to break up the modules.

Compiling dmd

Complete source code is provided to build the compiler. Follow these steps:

cd \dmd\src\dmd
make -f win32.mak

Compiling Phobos

Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

cd \dmd\src\phobos
make -f win32.mak DMD=\dmd\\bin\dmd


Code Coverage Analysis

Last update Sun Dec 30 20:34:43 2012

Code Coverage Analysis

A major part of the engineering of a professional software project is creating a test suite for it. Without some sort of test suite, it is impossible to know if the software works at all. The D language has many features to aid in the creation of test suites, such as unit tests and contract programming. But there's the issue of how thoroughly the test suite tests the code. The profiler can give valuable information on which functions were called, and by whom. But to look inside a function, and determine which statements were executed and which were not, requires a code coverage analyzer.

A code coverage analyzer will help in these ways:

  1. Expose code that is not exercised by the test suite. Add test cases that will exercise it.
  2. Identify code that is unreachable. Unreachable code is often the leftover result of program design changes. Unreachable code should be removed, as it can be very confusing to the maintenance programmer.
  3. It can be used to track down why a particular section of code exists, as the test case that causes it to execute will illuminate why.
  4. Since execution counts are given for each line, it is possible to use the coverage analysis to reorder the basic blocks in a function to minimize jmps in the most used path, thus optimizing it.

Experience with code coverage analyzers show that they dramatically reduce the number of bugs in shipping code. But it isn't a panacea, a code coverage analyzer won't help with:

  1. Identifying race conditions.
  2. Memory consumption problems.
  3. Pointer bugs.
  4. Verifying that the program got the correct result.

Code coverage analysers are available for many popular languages such as C++, but they are often third party products that integrate poorly with the compiler, and are often very expensive. A big problem with third party products is, in order to instrument the source code, they must include what is essentially a full blown compiler front end for the same language. Not only is this an expensive proposition, it often winds up out of step with the various compiler vendors as their implementations change and as they evolve various extensions. (gcov, the Gnu coverage analyzer, is an exception as it is both free and is integrated into gcc.)

The D code coverage analyser is built in as part of the D compiler. Therefore, it is always in perfect synchronization with the language implementation. It's implemented by establishing a counter for each line in each module compiled with the -cov switch. Code is inserted at the beginning of each statement to increment the corresponding counter. When the program finishes, a static destructor for std.cover collects all the counters, merges it with the source files, and writes the reports out to listing (.lst) files.

For example, consider the Sieve program:

/* Eratosthenes Sieve prime number calculation. */

import std.stdio;

bit flags[8191];

int main()
{   int     i, prime, k, count, iter;

    writefln("10 iterations");
    for (iter = 1; iter <= 10; iter++)
    {	count = 0;
    flags[] = true;
    for (i = 0; i < flags.length; i++)
    {   if (flags[i])
        {	prime = i + i + 3;
        k = i + prime;
        while (k < flags.length)
        {
            flags[k] = false;
            k += prime;
        }
        count += 1;
        }
    }
    }
    writefln("%d primes", count);
    return 0;
}

Compile and run it with:

dmd sieve -cov
sieve

The output file will be created called sieve.lst, the contents of which are:

       |/* Eratosthenes Sieve prime number calculation. */
       |
       |import std.stdio;
       |
       |bit flags[8191];
       |
       |int main()
      5|{   int     i, prime, k, count, iter;
       |
      1|    writefln("10 iterations");
     22|    for (iter = 1; iter <= 10; iter++)
     10|    {   count = 0;
     10|        flags[] = true;
 163840|        for (i = 0; i < flags.length; i++)
  81910|        {   if (flags[i])
  18990|            {   prime = i + i + 3;
  18990|                k = i + prime;
 168980|                while (k < flags.length)
       |                {
 149990|                    flags[k] = false;
 149990|                    k += prime;
       |                }
  18990|                count += 1;
       |            }
       |        }
       |    }
      1|    writefln("%d primes", count);
      1|    return 0;
       |}
sieve.d is 100% covered

The numbers to the left of the | are the execution counts for that line. Lines that have no executable code are left blank. Lines that have executable code, but were not executed, have a "0000000" as the execution count. At the end of the .lst file, the percent coverage is given.

There are 3 lines with an exection count of 1, these were each executed once. The declaration line for i, prime, etc., has 5 because there are 5 declarations, and the initialization of each declaration counts as one statement.

The first for loop shows 22. This is the sum of the 3 parts of the for header. If the for header is broken up into 3 lines, the data is similarly divided:

      1|    for (iter = 1;
     11|         iter <= 10;
     10|         iter++)

which adds up to 22.

e1&&e2 and e1||e2 expressions conditionally execute the rvalue e2. Therefore, the rvalue is treated as a separate statement with its own counter:

        |void foo(int a, int b)
        |{
       5|   bar(a);
       8|   if (a && b)
       1|	bar(b);
        |}

By putting the rvalue on a separate line, this illuminates things:

        |void foo(int a, int b)
        |{
       5|   bar(a);
       5|   if (a &&
       3|	b)
       1|	bar(b);
        |}

Similarly, for the e?e1:e2 expressions, e1 and e2 are treated as separate statements.

Controlling the Coverage Analyser

The behavior of the coverage analyser can be controlled through the std.cover module.

When the -cov switch is thrown, the version identifier D_Coverage is defined.

References

Wikipedia


rdmd

rdmd is a program to compile, cache and execute D source code files or 'pseudo shell scripts' (using the she-bang syntax with dmd v0.146 or above) on Linux and Windows systems.

It will cache the executable in the /tmp directory by default and will re-compile the executable if any of the source file, the compiler or rdmd itself is newer than the cached executable. It can optionally use gdmd if specified, but uses dmd by default.

Usage:

rdmd [D compiler arguments] [rdmd arguments] progfile.d [program arguments]

rdmd arguments:

--help
This message
--force
Force re-compilation of source code [default = do not force]
--compiler=(dmd|gdmd)
Specify compiler [default = dmd]
--tmpdir=tmp_dir_path
Specify directory to store cached program and other temporaries [default = /tmp]

Notes:

  • dmd or gdmd must be in the current user context $PATH
  • rdmd does not support execution of D source code via stdin
  • rdmd will only compile and execute files with a '.d' file extension
  • rdmd's functionality will probably get folded into dmd itself

written by Dave Fladebo and Robert Mariottini

Copyright © 1999-2006 by Digital Mars, All Rights Reserved | Page generated by Ddoc. | Comments


windbg Debugger

Last update Sun Dec 30 20:34:43 2012

Debugging D on Windows

The Microsoft Windows debugger \windows\bin\windbg.exe can be used to symbolically debug D programs, even though it is a C++ debugger. Versions of windbg.exe other than the one supplied may not work with D. (Jascha Wetzel's Ddbg for Windows is also available.)

To prepare a program for symbolic debugging, compile with the -gc switch:

dmd myprogram -gc

To invoke the debugger on it:

windbg myprogram args...

where args... are the command line arguments to myprogram.exe.

When the debugger comes up, entering the command in the command window:

g _Dmain

will execute the program up until the entry into main(). From thence, pressing the F10 key will single step each line of code.

Basic Commands:

F5
Go until breakpoint, an exception is thrown, or the end of the program.
F7
Continue until cursor.
F8
Single step, stepping into function calls.
F10
Single step, stepping over function calls.

For more comprehensive information on windbg, consult the file \windows\bin\windbg.hlp.


htod

Last update Sun Dec 30 20:34:43 2012

htod

While D is binary compatible with C code, it cannot compile C code nor C header files. In order for D to link with C code, the C declarations residing in C header files need to be converted to a D module. htod is a migration tool to aid in convering C header files.

htod is built from the front end of the Digital Mars C and C++ compiler. It works just like a C or C++ compiler except that its output is a D module rather than object code.

The macro __HTOD__ is predefined and set to 1, which is handy for improving C header files to give better D output.

Download

htod

Usage

htod cheader.h [dimport.d] [-cpp] [-hc] [-hi] [-hs] [-ht] { C compiler switches }

where:

cheader.h
C or C++ header input file
dimport.d
D source code output file (defaults to cheader.d)
-cpp
Indicates a C++ header file
-hc
By default, htod will insert the C and C++ declarations in a file into the output file prefixed by //C . -hc will suppress this. Use only if you're confident that htod is generating the correct output file (such as if the header file was modified with __HTOD__).
-hi
By default, htod will represent a #include "file" with a corresponding import statement. The -hi will cause the declarations in the included file to be converted to D declarations as well. The declarations in all included files are parsed regardless. -hi is handy when replacing an entire hierarchy of include files with a single D import. System includes like #include <file> are not affected by -hi. See also -hs.
-ht
By default, htod will write types using typedef names as using those names. -ht will cause the underlying types to be used instead. This is very useful for "drilling down" layers of macros, typedefs, and #includes to find out the underlying type.
-hs
Works just like -hi, except that system includes are migrated as well.
C compiler switches
C or C++ compiler switches, such as -D and -I as documented for dmc.

Example

The C test.h file:

unsigned u;
#define MYINT int
void bar(int x, long y, long long z);

Translated with:

htod test.h

Produces the file test.d:

/* Converted to D from test.h by htod */
module test;
//C     unsigned u;
extern (C):
uint u;
//C     #define MYINT int
//C     void bar(int x, long y, long long z);
alias int MYINT;
void  bar(int x, int y, long z);

The C declarations are prefixed by the string "//C ".

Type Mappings

C types are mapped as follows. These mappings are correct for Digital Mars C/C++, but may not be correct for your C compiler. D basic types have fixed sizes, while C basic type sizes are implementation defined.

Mapping C to D types
C type | D type
void | void
_Bool | bool
wchar_t | wchar
char | char
signed char | byte
unsigned char | ubyte
short | short
unsigned short | ushort
int | int
unsigned | uint
long | int
unsigned long | uint
long long | long
unsigned long long | ulong
float | float
double | double
long double | real
_Imaginary float | ifloat
_Imaginary double | idouble
_Imaginary long double | ireal
_Complex float | cfloat
_Complex double | cdouble
_Complex long double | creal

Limitations

There is no one to one correspondence of C declarations to D declarations. A review of the D module output will be necessary to ensure the right decisions are made. Furthermore:

  1. Whereever practical, C headers should be written using typedef's and enum's rather than macros. htod will attempt to convert simple macro #define's to alias and const declarations. Even so, macros are fully expanded before further analysis.
  2. No attempt is made to convert C conditional compilation into D version or static if declarations.
  3. No output is generated for false conditional compilation sections.
  4. htod converts declarations only, it does not convert C code.
  5. Declarations with C++ linkage cannot be converted. A C interface must be made for any C++ code.
  6. C language extensions present in the C .h file may not be recognized.
  7. Pragmas are not translated.
  8. The tag names are assumed to not collide with names in the regular name space.
  9. Any character data that is not ASCII will need to be converted as necessary to UTF.
  10. The C char type is assumed to map to the D char type. However, these should be examined individually to see if they should instead be translated to byte or ubyte types. Whether the C char type is signed or unsigned is implementation defined. The D char type is unsigned.
  11. Named C enum members are not inserted into the surrounding scope as they are in C.
  12. D modules are each in their own name space, but C header files are all in the same global name space. This means that D references to names defined in other modules may need to be qualified.

Bugs

  1. Anything other than the default struct member alignment is not accounted for.
  2. No Linux version.


Glossary

Last update Sun Dec 30 20:34:43 2012

Glossary

BLIT (Block Transfer)
Also known as BLT, blit refers to copying memory byte by byte. In C, this is referred to as a memcpy operation. The name originated with the BLT instruction on the DEC PDP-10 computer.
CTFE (Compile Time Function Evaluation)
Refers to the ability to execute regular D functions at compile time rather than at run time.
COW (Copy On Write)
COW is a memory allocation strategy where arrays are copied if they are to be modified.
Functor
An user-defined type (struct or class) that defines the function call operator ( in D) and as such can be used similarly to a function.
GC (Garbage Collection)
Garbage collection is the common name for the term automatic memory management. Memory can be allocated and used, and the GC will automatically free any chunks of memory no longer referred to. In contrast, explicit memory management is where the programmer must carefully match up each allocation with one and only one free.
Higher-order function
A function that either accepts another function as a parameter, returns a function, or both.
Illegal
A code construct is illegal if it does not conform to the D language specification. This may be true even if the compiler or runtime fails to detect the error.
Implementation Defined Behavior
This is variation in behavior of the D language in a manner that is up to the implementor of the language. An example of implementation defined behavior would be the size in bytes of a pointer: on a 32 bit machine it would be 4 bytes, on a 64 bit machine it would be 8 bytes. Minimizing implementation defined behavior in the language will maximize the portability of code.
NRVO (Named Return Value Optimization)

NRVO is a technique invented by Walter Bright around 1991 (the term for it was coined later) to minimize copying of struct data. Functions normally return their function return values in registers. For structs, however, they often are too big to fit in registers. The usual solution to this is to pass to the function a hidden pointer to a struct instance in the caller's stack frame, and the return value is copied there. For example:

struct S { int a, b, c, d; }

S foo()
{
    S result;
    result.a = 3;
    return result;
}

void test()
{
    S s = foo();
}

is rewritten as:

S* foo(S* hidden)
{
    S result;
    result.a = 3;
    *hidden = result;
    return hidden;
}

void test()
{
    S tmp;
    S s = *foo(&tmp);
}

This rewrite gives us an extra temporary object tmp, and copies the struct contents twice. What NRVO does is recognize that the sole purpose of result is to provide a return value, and so all references to result can be replaced with *hidden. foo is then rewritten as:

S* foo(S* hidden)
{
    hidden.a = 3;
    return hidden;
}

A further optimization is done on the call to foo to eliminate the other copy, giving:

void test()
{
    S s;
    foo(&s);
}

The result is written directly into the destination s, instead of passing through two other instances.

POD (Plain Old Data)
Refers to a struct that contains no hidden members, does not have virtual functions, does not inherit, has no destructor, and can be initialized and copied via simple bit copies. D structs are POD.
Predicate
A function or delegate returning a Boolean result. Predicates can be nullary (take no arguments), unary (take one argument), binary (take two arguments), or n-ary (take n arguments). Usually predicates are mentioned within the context of higher-order functions, which accept predicates as parameters.
RAII (Resource Acquisition Is Initialization)
RAII refers to the technique of having the destructor of a class object called when the object goes out of scope. The destructor then releases any resources acquired by that object. RAII is commonly used for resources that are in short supply or that must have a predictable point when they are released. RAII objects in D are created using the scope storage class.
SFINAE (Substitution Failure Is Not An Error)
If template argument deduction results in a type that is not valid, that specialization of the template is not considered further. It is not a compile error. See also SFINAE.
TMP (Template Metaprogramming)
TMP is using the template features of the language to execute programs at compile time rather than runtime.
UB (Undefined Behavior)
Undefined behavior happens when an illegal code construct is executed. Undefined behavior can include random, erratic results, crashes, faulting, etc.


ASCII Table

Last update Sun Dec 30 20:34:43 2012

ASCII Table

      00  10  20  30  40  50  60  70

 00  NUL DLE SPC   0   @   P   `   p
 01  SOH DC1   !   1   A   Q   a   q
 02  STX DC2   "   2   B   R   b   r
 03  ETX DC3   #   3   C   S   c   s
 04  EOT DC4   $   4   D   T   d   t
 05  ENQ NAK   %   5   E   U   e   u
 06  ACK SYN   &   6   F   V   f   v
 07  BEL ETB   '   7   G   W   g   w
 08  BS  CAN   (   8   H   X   h   x
 09  TAB EM    )   9   I   Y   i   y
 0A  LF  SUB   *   :   J   Z   j   z
 0B  VT  ESC   +   ;   K   [   k   {
 0C  FF  FS    ,   <   L   \   l   |
 0D  CR  GS    -   =   M   ]   m   }
 0E  SO  RS    .   >   N   ^   n   ~
 0F  SI  US    /   ?   O   _   o DEL


Acknowledgements

Last update Sun Dec 30 20:34:43 2012

Acknowledgements

The following (incomplete) list of people have contributed to the D language project; with ideas, code, expertise, marketing, inspiration and moral support.

Andrei Alexandrescu, Kris Bell, Don Clugston, Hauke Duden, Bruce Eckel, Eric Engstrom, Dave Fladebo, David Friedman, Stewart Gordon, Christian Hartung, David Held, Ben Hinkle, Kazuhiro Inaba, Jan Knepper, Thomas Kuehne, Helmut Leitner, Lubomir Litchev, Bartosz Milewski, Christopher E. Miller, Pavel Minayev, Antonio Monteiro, Paul Nash, Pat Nelson, Derek Parnell, Burton Radons, Tim Rentsch, Fabio Riccardi, Brad Roberts, Bob Taniguchi, Bob W, John Whited, Matthew Wilson, Peter Zatloukal


Lexical

Last update Sun Dec 30 20:34:42 2012

Lexical

The lexical analysis is independent of the syntax parsing and the semantic analysis. The lexical analyzer splits the source text up into tokens. The lexical grammar describes what those tokens are. The grammar is designed to be suitable for high speed scanning, it has a minimum of special case rules, there is only one phase of translation, and to make it easy to write a correct scanner for. The tokens are readily recognizable by those familiar with C and C++.

Source Text

D source text can be in one of the following formats:
  • ASCII
  • UTF-8
  • UTF-16BE
  • UTF-16LE
  • UTF-32BE
  • UTF-32LE
UTF-8 is a superset of traditional 7-bit ASCII. One of the following UTF BOMs (Byte Order Marks) can be present at the beginning of the source text:

UTF Byte Order Marks
Format | BOM
UTF-8 | EF BB BF
UTF-16BE | FE FF
UTF-16LE | FF FE
UTF-32BE | 00 00 FE FF
UTF-32LE | FF FE 00 00
ASCII | no BOM

If the source file does not start with a BOM, then the first character must be less than or equal to U0000007F.

There are no digraphs or trigraphs in D.

The source text is decoded from its source representation into Unicode Characters. The Characters are further divided into: WhiteSpace, EndOfLine, Comments, SpecialTokenSequences, Tokens, all followed by EndOfFile.

The source text is split into tokens using the maximal munch technique, i.e., the lexical analyzer tries to make the longest token it can. For example >> is a right shift token, not two greater than tokens. An exception to this rule is that a .. embedded inside what looks like two floating point literals, as in 1..2, is interpreted as if the .. was separated by a space from the first integer.

Character Set

Character
    any Unicode character

End of File

EndOfFile:
    physical end of the file
    \u0000
    \u001A
The source text is terminated by whichever comes first.

End of Line

EndOfLine:
    \u000D
    \u000A
    \u000D \u000A
    EndOfFile
There is no backslash line splicing, nor are there any limits on the length of a line.

White Space

WhiteSpace:
    Space
    Space WhiteSpace

Space:
    \u0020
    \u0009
    \u000B
    \u000C

Comments

Comment:
    BlockComment
    LineComment
    NestingBlockComment

BlockComment
    /* Characters */

LineComment
    // Characters EndOfLine

NestingBlockComment:
    /+ NestingBlockCommentCharacters +/

NestingBlockCommentCharacters:
    NestingBlockCommentCharacter
    NestingBlockCommentCharacter NestingBlockCommentCharacters

NestingBlockCommentCharacter:
    Character
    NestingBlockComment

Characters:
    Character
    Character Characters

D has three kinds of comments:

  1. Block comments can span multiple lines, but do not nest.
  2. Line comments terminate at the end of the line.
  3. Nesting block comments can span multiple lines and can nest.

The contents of strings and comments are not tokenized. Consequently, comment openings occurring within a string do not begin a comment, and string delimiters within a comment do not affect the recognition of comment closings and nested "/+" comment openings. With the exception of "/+" occurring within a "/+" comment, comment openings within a comment are ignored.

a = /+ // +/ 1;    // parses as if 'a = 1;'
a = /+ "+/" +/ 1"; // parses as if 'a = " +/ 1";'
a = /+ /* +/ */ 3; // parses as if 'a = */ 3;'
Comments cannot be used as token concatenators, for example, abc/**/def is two tokens, abc and def, not one abcdef token.

Tokens

Token:
    Identifier
    StringLiteral
    CharacterLiteral
    IntegerLiteral
    FloatLiteral
    Keyword
    /
    /=
    .
    ..
    ...
    &
    &=
    &&
    |
    |=
    ||
    -
    -=
    --
    +
    +=
    ++
    <
    <=
    <<
    <<=
    <>
    <>=
    >
    >=
    >>=
    >>>=
    >>
    >>>
    !
    !=
    !<>
    !<>=
    !<
    !<=
    !>
    !>=
    (
    )
    [
    ]
    {
    }
    ?
    ,
    ;
    :
    $
    =
    ==
    *
    *=
    %
    %=
    ^
    ^=
    ~
    ~=

Identifiers

Identifier:
    IdentifierStart
    IdentifierStart IdentifierChars

IdentifierChars:
    IdentifierChar
    IdentifierChar IdentifierChars

IdentifierStart:
    _
    Letter
    UniversalAlpha

IdentifierChar:
    IdentifierStart
    0
    NonZeroDigit
Identifiers start with a letter, _, or universal alpha, and are followed by any number of letters, _, digits, or universal alphas. Universal alphas are as defined in ISO/IEC 9899:1999(E) Appendix D. (This is the C99 Standard.) Identifiers can be arbitrarily long, and are case sensitive. Identifiers starting with __ (two underscores) are reserved.

String Literals

StringLiteral:
    WysiwygString
    AlternateWysiwygString
    DoubleQuotedString
   EscapeSequence
    HexString

WysiwygString:
    r" WysiwygCharacters " StringPostfixopt

AlternateWysiwygString:
    ` WysiwygCharacters ` StringPostfixopt

WysiwygCharacters:
    WysiwygCharacter
    WysiwygCharacter WysiwygCharacters

WysiwygCharacter:
    Character
    EndOfLine

DoubleQuotedString:
    " DoubleQuotedCharacters " StringPostfixopt

DoubleQuotedCharacters:
    DoubleQuotedCharacter
    DoubleQuotedCharacter DoubleQuotedCharacters

DoubleQuotedCharacter:
    Character
    EscapeSequence
    EndOfLine

EscapeSequence:
    \'
    \"
    \?
    \\
    \a
    \b
    \f
    \n
    \r
    \t
    \v
    \ EndOfFile
    \x HexDigit HexDigit
    \ OctalDigit
    \ OctalDigit OctalDigit
    \ OctalDigit OctalDigit OctalDigit
    \u HexDigit HexDigit HexDigit HexDigit
    \U HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit
    NamedCharacterEntity

HexString:
    x" HexStringChars " StringPostfixopt

HexStringChars:
    HexStringChar
    HexStringChar HexStringChars

HexStringChar:
    HexDigit
    WhiteSpace
    EndOfLine

StringPostfix:
    c
    w
    d

A string literal is either a double quoted string, a wysiwyg quoted string, an escape sequence, or a hex string.

In all string literal forms, an EndOfLine is regarded as a single \n character.

Wysiwyg Strings

Wysiwyg quoted strings are enclosed by r" and ". All characters between the r" and " are part of the string. There are no escape sequences inside r" ":

r"hello"
r"c:\root\foo.exe"
r"ab\n" // string is 4 characters,
        // 'a', 'b', '\', 'n'

An alternate form of wysiwyg strings are enclosed by backquotes, the ` character. The ` character is not available on some keyboards and the font rendering of it is sometimes indistinguishable from the regular ' character. Since, however, the ` is rarely used, it is useful to delineate strings with " in them.

`hello`
`c:\root\foo.exe`
`ab\n`  // string is 4 characters,
        // 'a', 'b', '\', 'n'

Double Quoted Strings

Double quoted strings are enclosed by "". Escape sequences can be embedded into them with the typical \ notation.
"hello"
"c:\\root\\foo.exe"
"ab\n"   // string is 3 characters,
         // 'a', 'b', and a linefeed
"ab
"        // string is 3 characters,
         // 'a', 'b', and a linefeed

Escape Strings

Escape strings start with a \ and form an escape character sequence. Adjacent escape strings are concatenated:

\n | the linefeed character
\t | the tab character
\" | the double quote character
\012 | octal
\x1A | hex
\u1234 | wchar character
\U00101234 | dchar character
\&reg; | ® dchar character
\r\n | carriage return | line feed

Undefined escape sequences are errors. Although string literals are defined to be composed of UTF characters, the octal and hex escape sequences allow the insertion of arbitrary binary data. \u and \U escape sequences can only be used to insert valid UTF characters.

Hex Strings

Hex strings allow string literals to be created using hex data. The hex data need not form valid UTF characters.

x"0A"              // same as "\x0A"
x"00 FBCD 32FD 0A" // same as
               // "\x00\xFB\xCD\x32\xFD\x0A"
Whitespace and newlines are ignored, so the hex data can be easily formatted. The number of hex characters must be a multiple of 2.

Adjacent strings are concatenated with the ~ operator, or by simple juxtaposition:

"hello " ~ "world" ~ \n // forms the string
       // 'h','e','l','l','o',' ',
       // 'w','o','r','l','d',linefeed
The following are all equivalent:
"ab" "c"
r"ab" r"c"
r"a" "bc"
"a" ~ "b" ~ "c"
\x61"bc"

The optional StringPostfix character gives a specific type to the string, rather than it being inferred from the context. This is useful when the type cannot be unambiguously inferred, such as when overloading based on string type. The types corresponding to the postfix characters are:

String Literal Postfix Characters
Postfix | Type | Aka
c | char[] | string
w | wchar[] | wstring
d | dchar[] | dstring
"hello"c  // string
"hello"w  // wstring
"hello"d  // dstring

The string literals are assembled as UTF-8 char arrays, and the postfix is applied to convert to wchar or dchar as necessary as a final step.

String literals are read only. Writes to string literals cannot always be detected, but cause undefined behavior.

Character Literals

CharacterLiteral:
    ' SingleQuotedCharacter '

SingleQuotedCharacter:
    Character
    EscapeSequence
Character literals are a single character or escape sequence enclosed by single quotes, ' '.

Integer Literals

IntegerLiteral:
    Integer
    Integer IntegerSuffix

Integer:
    DecimalInteger
    BinaryInteger
  OctalInteger
    HexadecimalInteger

IntegerSuffix:
    L
    u
    U
    Lu
    LU
    uL
    UL

DecimalInteger:
    0
    NonZeroDigit
    NonZeroDigit DecimalDigitsUS

BinaryInteger:
    BinPrefix BinaryDigits

BinPrefix:
    0b
    0B

OctalInteger:
    0 OctalDigitsUS

HexadecimalInteger:
    HexPrefix HexDigitsNoSingleUS

NonZeroDigit:
    1
    2
    3
    4
    5
    6
    7
    8
    9

DecimalDigits:
    DecimalDigit
    DecimalDigit DecimalDigits

DecimalDigitsUS:
    DecimalDigitUS
    DecimalDigitUS DecimalDigitsUS

DecimalDigitsNoSingleUS:
    DecimalDigit
    DecimalDigit DecimalDigitsUS
    DecimalDigitsUS DecimalDigit

DecimalDigitsNoStartingUS:
    DecimalDigit
    DecimalDigit DecimalDigitsUS

DecimalDigit:
    0
    NonZeroDigit

DecimalDigitUS:
    DecimalDigit
    _

BinaryDigitsUS:
    BinaryDigitUS
    BinaryDigitUS BinaryDigitsUS

BinaryDigit:
    0
    1

BinaryDigitUS:
    BinaryDigit
    _

OctalDigits:
    OctalDigit
    OctalDigit OctalDigits

OctalDigitsUS:
    OctalDigitUS
    OctalDigitUS OctalDigitsUS

OctalDigit:
    0
    1
    2
    3
    4
    5
    6
    7

OctalDigitUS:
    OctalDigit
    _

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigitsUS:
    HexDigitUS
    HexDigitUS HexDigitsUS

HexDigitsNoSingleUS:
    HexDigit
    HexDigit HexDigitsUS
    HexDigitsUS HexDigit

HexDigit:
    DecimalDigit
    HexLetter

HexLetter:
    a
    b
    c
    d
    e
    f
    A
    B
    C
    D
    E
    F
    _

Integers can be specified in decimal, binary, octal, or hexadecimal.

Decimal integers are a sequence of decimal digits.

Binary integers are a sequence of binary digits preceded by a ‘0b’.

Octal integers are a sequence of octal digits preceded by a ‘0’.

Hexadecimal integers are a sequence of hexadecimal digits preceded by a ‘0x’.

Integers can have embedded ‘_’ characters, which are ignored. The embedded ‘_’ are useful for formatting long literals, such as using them as a thousands separator:

123_456       // 123456
1_2_3_4_5_6_  // 123456

Integers can be immediately followed by one ‘L’ or one of ‘u’ or ‘U’ or both. Note that there is no ‘l’ suffix.

The type of the integer is resolved as follows:

Decimal Literal Types
Decimal Literal | Type
0 .. 2_147_483_647 | int
2_147_483_648 .. 9_223_372_036_854_775_807L | long
Decimal Literal, L Suffix | Type
0L .. 9_223_372_036_854_775_807L | long
Decimal Literal, U Suffix | Type
0U .. 4_294_967_296U | uint
4_294_967_296U .. 18_446_744_073_709_551_615UL | ulong
Decimal Literal, UL Suffix | Type
0UL .. 18_446_744_073_709_551_615UL | ulong
Non-Decimal Literal | Type
0x0 .. 0x7FFF_FFFF | int
0x8000_0000 .. 0xFFFF_FFFF | uint
0x1_0000_0000 .. 0x7FFF_FFFF_FFFF_FFFF | long
0x8000_0000_0000_0000 .. 0xFFFF_FFFF_FFFF_FFFF | ulong
Non-Decimal Literal, L Suffix | Type
0x0L .. 0x7FFF_FFFF_FFFF_FFFFL | long
0x8000_0000_0000_0000L .. 0xFFFF_FFFF_FFFF_FFFFL | ulong
Non-Decimal Literal, U Suffix | Type
0x0U .. 0xFFFF_FFFFU | uint
0x1_0000_0000UL .. 0xFFFF_FFFF_FFFF_FFFFUL | ulong
Non-Decimal Literal, UL Suffix | Type
0x0UL .. 0xFFFF_FFFF_FFFF_FFFFUL | ulong

Floating Literals

FloatLiteral:
    Float
    Float Suffix
    Integer ImaginarySuffix
    Integer FloatSuffix ImaginarySuffix
    Integer RealSuffix ImaginarySuffix

Float:
    DecimalFloat
    HexFloat

DecimalFloat:
    LeadingDecimal .
    LeadingDecimal . DecimalDigits
    DecimalDigits . DecimalDigitsNoSingleUS DecimalExponent
    . DecimalInteger
    . DecimalInteger DecimalExponent
    LeadingDecimal DecimalExponent

DecimalExponent
    DecimalExponentStart DecimalDigitsNoSingleUS

DecimalExponentStart
    e
    E
    e+
    E+
    e-
    E-

HexFloat:
    HexPrefix HexDigitsNoSingleUS . HexDigitsNoSingleUS HexExponent
    HexPrefix . HexDigitsNoSingleUS HexExponent
    HexPrefix HexDigitsNoSingleUS HexExponent

HexPrefix:
    0x
    0X

HexExponent:
    HexExponentStart DecimalDigitsNoSingleUS

HexExponentStart:
    p
    P
    p+
    P+
    p-
    P-

Suffix:
    FloatSuffix
    RealSuffix
    ImaginarySuffix
    FloatSuffix ImaginarySuffix
    RealSuffix ImaginarySuffix

FloatSuffix:
    f
    F

RealSuffix:
    L

ImaginarySuffix:
    i

LeadingDecimal:
    DecimalInteger
    0 DecimalDigitsNoSingleUS

Floats can be in decimal or hexadecimal format.

Hexadecimal floats are preceded with a 0x and the exponent is a p or P followed by a decimal number serving as the exponent of 2.

Floating literals can have embedded ‘_’ characters, which are ignored. The embedded ‘_’ are useful for formatting long literals to make them more readable, such as using them as a thousands separator:

123_456.567_8         // 123456.5678
1_2_3_4_5_6_._5_6_7_8 // 123456.5678
1_2_3_4_5_6_._5e-6_   // 123456.5e-6

Floating literals with no suffix are of type double. Floats can be followed by one f, F, or L suffix. The f or F suffix means it is a float, and L means it is a real.

If a floating literal is followed by i, then it is an ireal (imaginary) type.

Examples:

0x1.FFFFFFFFFFFFFp1023 // double.max
0x1p-52                // double.epsilon
1.175494351e-38F       // float.min
6.3i                   // idouble 6.3
6.3fi                  // ifloat 6.3
6.3Li                  // ireal 6.3

It is an error if the literal exceeds the range of the type. It is not an error if the literal is rounded to fit into the significant digits of the type.

Complex literals are not tokens, but are assembled from real and imaginary expressions during semantic analysis:

4.5 + 6.2i  // complex number (phased out)

Keywords

Keywords are reserved identifiers.
Keyword:
    abstract
    alias
    align
    asm
    assert
    auto

    body
    bool
    break
    byte

    case
    cast
    catch
    cdouble
    cent
    cfloat
    char
    class
    const
    continue
    creal

    dchar
    debug
    default
    delegate
    delete
    deprecated
    do
    double

    else
    enum
    export
    extern

    false
    final
    finally
    float
    for
    foreach
    foreach_reverse
    function

    goto

    idouble
    if
    ifloat
    import
    in
    inout
    int
    interface
    invariant
    ireal
    is

    lazy
    long

    macro
    mixin
    module

    new
    null

    out
    override

    package
    pragma
    private
    protected
    public

    real
    ref
    return

    scope
    short
    static
    struct
    super
    switch
    synchronized

    template
    this
    throw
    true
    try
    typedef
    typeid
    typeof

    ubyte
    ucent
    uint
    ulong
    union
    unittest
    ushort

    version
    void
    volatile

    wchar
    while
    with

Special Tokens

These tokens are replaced with other tokens according to the following table:

Special Tokens
Special Token | Replaced with...
__FILE__ | string literal containing source file name
__LINE__ | integer literal of the current source line number
__DATE__ | string literal of the date of compilation "mmm dd yyyy"
__TIME__ | string literal of the time of compilation "hh:mm:ss"
__TIMESTAMP__ | string literal of the date and time of compilation "www mmm dd hh:mm:ss yyyy"
__VENDOR__ | Compiler vendor string, such as "Digital Mars D"
__VERSION__ | Compiler version as an integer, such as 2001

Special Token Sequences

SpecialTokenSequence:
    # line IntegerLiteral EndOfLine
    # line IntegerLiteral Filespec EndOfLine

Filespec:
    " Characters "

Special token sequences are processed by the lexical analyzer, may appear between any other tokens, and do not affect the syntax parsing.

There is currently only one special token sequence, #line.

This sets the source line number to IntegerLiteral, and optionally the source file name to Filespec, beginning with the next line of source text. The source file and line number is used for printing error messages and for mapping generated code back to the source for the symbolic debugging output.

For example:

int #line 6 "foo\bar"
x;  // this is now line 6 of file foo\bar

Note that the backslash character is not treated specially inside Filespec strings.


Table of Contents

Last update Sun Dec 30 20:34:44 2012

Table of Contents

This is the specification for the D Programming Language. For more information see d-programming-language.org.

This is also available as a Mobi ebook or as a Kindle ebook .

  • Introduction
  • Lexical
  • Modules
  • Declarations
  • Types
  • Properties
  • Attributes
  • Pragmas
  • Expressions
  • Statements
  • Arrays
  • Associative Arrays
  • Structs & Unions
  • Classes
  • Interfaces
  • Enums
  • Const and Immutable
  • Functions
  • Operator Overloading
  • Templates
  • Template Mixins
  • Contract Programming
  • Conditional Compilation
  • Traits
  • Error Handling
  • Unit Tests
  • Garbage Collection
  • Floating Point
  • Inline Assembler
  • Embedded Documentation
  • Interfacing To C
  • Interfacing To C++
  • Portability Guide
  • Named Character Entities
  • Memory Safety
  • Application Binary Interface


Introduction

Last update Sun Dec 30 20:34:44 2012

Introduction

The D programming language is a general purpose systems programming language. To that end, a D program is a collection of modules that can be compiled separately to native code that is combined with libraries and compiled C code by a linker to create a native executable.

Phases of Compilation

The process of compiling is divided into multiple phases. Each phase has no dependence on subsequent phases. For example, the scanner is not perturbed by the semantic analyzer. This separation of the passes makes language tools like syntax directed editors relatively easy to produce. It also is possible to compress D source by storing it in ‘tokenized’ form.
  1. source character set
    The source file is checked to see what character set it is, and the appropriate scanner is loaded. ASCII and UTF formats are accepted.
  2. script line
    If the first line starts with #! then the first line is ignored.
  3. lexical analysis
    The source file is divided up into a sequence of tokens. Special tokens are replaced with other tokens. SpecialTokenSequences are processed and removed.
  4. syntax analysis
    The sequence of tokens is parsed to form syntax trees.
  5. semantic analysis
    The syntax trees are traversed to declare variables, load symbol tables, assign types, and in general determine the meaning of the program.
  6. optimization
    Optimization is an optional pass that tries to rewrite the program in a semantically equivalent, but faster executing, version.
  7. code generation
    Instructions are selected from the target architecture to implement the semantics of the program. The typical result will be an object file, suitable for input to a linker.


Modules

Last update Sun Dec 30 20:34:42 2012

Modules

Module:
    ModuleDeclaration DeclDefs
    DeclDefs

DeclDefs:
    DeclDef
    DeclDef DeclDefs

DeclDef:
    AttributeSpecifier
    ImportDeclaration
    EnumDeclaration
    ClassDeclaration
    InterfaceDeclaration
    AggregateDeclaration
    Declaration
    Constructor
    Destructor
    UnitTest
    StaticConstructor
    StaticDestructor
    ConditionalDeclaration
    DebugSpecification
    VersionSpecification
    StaticAssert
    TemplateDeclaration
    TemplateMixinDeclaration
    TemplateMixin
    MixinDeclaration
    ;

Modules have a one-to-one correspondence with source files. The module name is the file name with the path and extension stripped off.

Modules automatically provide a namespace scope for their contents. Modules superficially resemble classes, but differ in that:

  • There's only one instance of each module, and it is statically allocated.
  • There is no virtual table.
  • Modules do not inherit, they have no super modules, etc.
  • Only one module per file.
  • Module symbols can be imported.
  • Modules are always compiled at global scope, and are unaffected by surrounding attributes or other modifiers.

Modules can be grouped together in hierarchies called packages.

Modules offer several guarantees:

  • The order in which modules are imported does not affect the semantics.
  • The semantics of a module are not affected by what imports it.
  • If a module C imports modules A and B, any modifications to B will not silently change code in C that is dependent on A.

Module Declaration

The ModuleDeclaration sets the name of the module and what package it belongs to. If absent, the module name is taken to be the same name (stripped of path and extension) of the source file name.

ModuleDeclaration:
    module ModuleFullyQualifiedName ;

ModuleFullyQualifiedName:
    ModuleName
    Packages . ModuleName

ModuleName:
    Identifier

Packages:
    PackageName
    Packages . PackageName

PackageName:
    Identifier

The Identifiers preceding the rightmost are the Packages that the module is in. The packages correspond to directory names in the source file path. Package names cannot be keywords, hence the corresponding directory names cannot be keywords, either.

If present, the ModuleDeclaration appears syntactically first in the source file, and there can be only one per source file.

Example:

module c.stdio;    // this is module stdio in the c package

By convention, package and module names are all lower case. This is because those names have a one-to-one correspondence with the operating system's directory and file names, and many file systems are not case sensitive. All lower case package and module names will minimize problems moving projects between dissimilar file systems.

Import Declaration

Symbols from one module are made available in another module by using the ImportDeclaration:

ImportDeclaration:
    import ImportList ;
    static import ImportList ;

ImportList:
    Import
    ImportBindings
    Import , ImportList

Import:
    ModuleFullyQualifiedName
    ModuleAliasIdentifier = ModuleFullyQualifiedName

ImportBindings:
    Import : ImportBindList

ImportBindList:
    ImportBind
    ImportBind , ImportBindList

ImportBind:
    Identifier
    Identifier = Identifier

ModuleAliasIdentifier:
    Identifier

There are several forms of the ImportDeclaration, from generalized to fine-grained importing.

The order in which ImportDeclarations occur has no significance.

ModuleFullyQualifiedNames in the ImportDeclaration must be fully qualified with whatever packages they are in. They are not considered to be relative to the module that imports them.

Basic Imports

The simplest form of importing is to just list the modules being imported:

import std.stdio; // import module stdio from the std package
import foo, bar;  // import modules foo and bar

void main()
{
    writefln("hello!\n");  // calls std.stdio.writefln
}

How basic imports work is that first a name is searched for in the current namespace. If it is not found, then it is looked for in the imports. If it is found uniquely among the imports, then that is used. If it is in more than one import, an error occurs.

module A;
void foo();
void bar();

module B;
void foo();
void bar();

module C;
import A;
void foo();
void test()
{ foo(); // C.foo() is called, it is found before imports are searched
  bar(); // A.bar() is called, since imports are searched
}

module D;
import A;
import B;
void test()
{ foo();   // error, A.foo() or B.foo() ?
  A.foo(); // ok, call A.foo()
  B.foo(); // ok, call B.foo()
}

module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo();   // call B.foo()
  A.foo(); // call A.foo()
  B.foo(); // call B.foo()
}

Public Imports

By default, imports are private. This means that if module A imports module B, and module B imports module C, then C's names are not searched for. An import can be specifically declared public, when it will be treated as if any imports of the module with the ImportDeclaration also import the public imported modules.

module A;
void foo() { }

module B;
void bar() { }

module C;
import A;
public import B;
...
foo();	// call  A.foo()
bar();	// calls B.bar()

module D;
import C;
...
foo();	// error, foo() is undefined
bar();	// ok, calls B.bar()

Static Imports

Basic imports work well for programs with relatively few modules and imports. If there are a lot of imports, name collisions can start occurring between the names in the various imported modules. One way to stop this is by using static imports. A static import requires one to use a fully qualified name to reference the module's names:

static import std.stdio;

void main()
{
 writefln("hello!");           // error, writefln is undefined
 std.stdio.writefln("hello!"); // ok, writefln is fully qualified
}

Renamed Imports

A local name for an import can be given, through which all references to the module's symbols must be qualified with:

import io = std.stdio;

void main()
{
 io.writefln("hello!");        // ok, calls std.stdio.writefln
 std.stdio.writefln("hello!"); // error, std is undefined
 writefln("hello!");           // error, writefln is undefined
}

Renamed imports are handy when dealing with very long import names.

Selective Imports

Specific symbols can be exclusively imported from a module and bound into the current namespace:

import std.stdio : writefln, foo = writef;

void main()
{
 std.stdio.writefln("hello!"); // error, std is undefined
 writefln("hello!");           // ok, writefln bound into current namespace
 writef("world");              // error, writef is undefined
 foo("world");                 // ok, calls std.stdio.writef()
 fwritefln(stdout, "abc");     // error, fwritefln undefined
}

static cannot be used with selective imports.

Renamed and Selective Imports

When renaming and selective importing are combined:

import io = std.stdio : foo = writefln;

void main()
{
 writefln("bar");           // error, writefln is undefined
 std.stdio.foo("bar");      // error, foo is bound into current namespace
 std.stdio.writefln("bar"); // error, std is undefined
 foo("bar");                // ok, foo is bound into current namespace,
                            // FQN not required
 io.writefln("bar");        // ok, io=std.stdio bound the name io in
                            // the current namespace to refer to the entire module
 io.foo("bar");             // error, foo is bound into current namespace,
                            // foo is not a member of io

Scoped Imports

Import declarations may be used at any scope. For example:

void main() {
  import std.stdio;
  writeln("bar");
}

The imports are looked up to satisfy any unresolved symbols at that scope. Imported symbols may hide symbols from outer scopes.

In function scopes, imported symbols only become visible after the import declaration lexically appears in the function body. In other words, imported symbols at function scope cannot be forward referenced.

void main() {
  void writeln(string) {}
  void foo() {
    writeln("bar"); // calls main.writeln
    import std.stdio;
    writeln("bar"); // calls std.stdio.writeln
    void writeln(string) {}
    writeln("bar"); // calls main.foo.writeln
  }
  writeln("bar"); // calls main.writeln
  std.stdio.writeln("bar");  // error, std is undefined
}

Module Scope Operator

Sometimes, it's necessary to override the usual lexical scoping rules to access a name hidden by a local name. This is done with the global scope operator, which is a leading ‘.’:
int x;

int foo(int x)
{
 if (y)
   return x;  // returns foo.x, not global x
 else
   return .x; // returns global x
}
The leading ‘.’ means look up the name at the module scope level.

Static Construction and Destruction

Static constructors are code that gets executed to initialize a module or a class before the main() function gets called. Static destructors are code that gets executed after the main() function returns, and are normally used for releasing system resources.

There can be multiple static constructors and static destructors within one module. The static constructors are run in lexical order, the static destructors are run in reverse lexical order.

Order of Static Construction

The order of static initialization is implicitly determined by the import declarations in each module. Each module is assumed to depend on any imported modules being statically constructed first. Other than following that rule, there is no imposed order on executing the module static constructors.

Cycles (circular dependencies) in the import declarations are allowed as long as not both of the modules contain static constructors or static destructors. Violation of this rule will result in a runtime exception.

Order of Static Construction within a Module

Within a module, the static construction occurs in the lexical order in which they appear.

Order of Static Destruction

It is defined to be exactly the reverse order that static construction was performed in. Static destructors for individual modules will only be run if the corresponding static constructor successfully completed.

Order of Unit tests

Unit tests are run in the lexical order in which they appear within a module.

Mixin Declaration

MixinDeclaration:
    mixin ( AssignExpression ) ;

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid DeclDefs, and is compiled as such.


Declarations

Last update Sun Dec 30 20:34:42 2012

Declarations

Declaration:
    TypedefDeclaration
    AliasDeclaration
    Decl

TypedefDeclaration:
    typedef Decl

AliasDeclaration:
    alias Decl

Decl:
    StorageClasses Decl
    BasicType Declarators ;
    BasicType Declarator FunctionBody
    AutoDeclaration

Declarators:
    DeclaratorInitializer
    DeclaratorInitializer , DeclaratorIdentifierList

DeclaratorInitializer:
    Declarator
    Declarator = Initializer

DeclaratorIdentifierList:
    DeclaratorIdentifier
    DeclaratorIdentifier , DeclaratorIdentifierList

DeclaratorIdentifier:
    Identifier
    Identifier = Initializer

BasicType:
    BasicTypeX
    .IdentifierList
    IdentifierList
    Typeof
    Typeof . IdentifierList

BasicTypeX:
    bool
    byte
    ubyte
    short
    ushort
    int
    uint
    long
    ulong
    char
    wchar
    dchar
    float
    double
    real
    ifloat
    idouble
    ireal
    cfloat
    cdouble
    creal
    void

BasicType2:
    *
    [ ]
    [ Expression ]
    [ Expression .. Expression ]
    [ Type ]
    delegate Parameters
    function Parameters

Declarator:
    BasicType2opt ( Declarator ) DeclaratorSuffixesopt
    BasicType2opt Identifier DeclaratorSuffixesopt

DeclaratorSuffixes:
    DeclaratorSuffix
    DeclaratorSuffix DeclaratorSuffixes

DeclaratorSuffix:
    [ ]
    [ Expression ]
    [ Type ]
    TemplateParameterListopt Parameters

IdentifierList:
    Identifier
    Identifier . IdentifierList
    TemplateInstance
    TemplateInstance . IdentifierList

StorageClasses:
    StorageClass
    StorageClass StorageClasses

StorageClass:
    abstract
    auto
    const
    deprecated
    extern
    final
    scope
    static
    synchronized

Property:
    @ PropertyIdentifier

PropertyIdentifier:
    property
    safe
    trusted
    system
    disable

Type:
    BasicType
    BasicType Declarator2

Declarator2:
    BasicType2opt DeclaratorSuffixesopt
    BasicType2opt ( Declarator2 ) DeclaratorSuffixesopt

Parameters:
    ( ParameterList )
    ( )

ParameterList:
    Parameter
    Parameter , ParameterList
    ...

Parameter:
    InOutopt BasicType Declarator
    InOutopt BasicType Declarator ...
    InOutopt BasicType Declarator = DefaultInitializerExpression
    InOutopt Type
    InOutopt Type ...

InOut:
    InOutX
    InOut InOutX

InOutX:
    auto
    const
    final
    in
    inout
    lazy
    out
    ref
    scope
    shared

MemberFunctionAttributes:
    MemberFunctionAttribute
    MemberFunctionAttribute MemberFunctionAttributes

MemberFunctionAttribute:
    const
    immutable
    inout
    shared
    FunctionAttribute

DefaultInitializerExpression:
    AssignExpression

Initializer:
    VoidInitializer
    NonVoidInitializer

NonVoidInitializer:
    AssignExpression
    ArrayInitializer
    StructInitializer

ArrayInitializer:
    [ ]
    [ ArrayMemberInitializations ]

ArrayMemberInitializations:
    ArrayMemberInitialization
    ArrayMemberInitialization ,
    ArrayMemberInitialization , ArrayMemberInitializations

ArrayMemberInitialization:
    NonVoidInitializer
    AssignExpression : NonVoidInitializer

StructInitializer:
    {  }
    { StructMemberInitializers }

StructMemberInitializers:
    StructMemberInitializer
    StructMemberInitializer ,
    StructMemberInitializer , StructMemberInitializers

StructMemberInitializer:
    NonVoidInitializer
    Identifier : NonVoidInitializer

Declaration Syntax

Declaration syntax generally reads right to left:

int x;    // x is an int
int* x;   // x is a pointer to int
int** x;  // x is a pointer to a pointer to int
int[] x;  // x is an array of ints
int*[] x; // x is an array of pointers to ints
int[]* x; // x is a pointer to an array of ints

Arrays read right to left as well:

int[3] x;     // x is an array of 3 ints
int[3][5] x;  // x is an array of 5 arrays of 3 ints
int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints

Pointers to functions are declared using the function keyword:

int function(char) x; // x is a pointer to
                     // a function taking a char argument
                     // and returning an int
int function(char)[] x; // x is an array of
                     // pointers to functions
                     // taking a char argument
                     // and returning an int

C-style array, function pointer and pointer to array declarations are possible as an alternative:

int x[3];          // x is an array of 3 ints
int x[3][5];       // x is an array of 3 arrays of 5 ints
int (*x[5])[3];    // x is an array of 5 pointers to arrays of 3 ints
int (*x)(char);    // x is a pointer to a function taking a char argument
                   // and returning an int
int (*[] x)(char); // x is an array of pointers to functions
                   // taking a char argument and returning an int

In a declaration declaring multiple symbols, all the declarations must be of the same type:

int x,y;   // x and y are ints
int* x,y;  // x and y are pointers to ints
int x,*y;  // error, multiple types
int[] x,y; // x and y are arrays of ints
int x[],y; // error, multiple types

Implicit Type Inference

AutoDeclaration:
    StorageClasses AutoDeclarationX ;

AutoDeclarationX:
    Identifier = Initializer
    AutoDeclarationX , Identifier = Initializer

If a declaration starts with a StorageClass and has a NonVoidInitializer from which the type can be inferred, the type on the declaration can be omitted.

static x = 3;      // x is type int
auto y = 4u;       // y is type uint
auto s = "string"; // s is type char[6]

class C { ... }

auto c = new C();  // c is a handle to an instance of class C

The NonVoidInitializer cannot contain forward references (this restriction may be removed in the future). The implicitly inferred type is statically bound to the declaration at compile time, not run time.

Type Defining

Strong types can be introduced with the typedef. Strong types are semantically a distinct type to the type checking system, for function overloading, and for the debugger.

typedef int myint;

void foo(int x) { . }
void foo(myint m) { . }

 .
myint b;
foo(b);         // calls foo(myint)
Typedefs can specify a default initializer different from the default initializer of the underlying type:
typedef int myint = 7;
myint m;        // initialized to 7

Type Aliasing

AliasDeclarations create a symbol that is an alias for another type, and can be used anywhere that other type may appear.

alias abc.Foo.bar myint;

Aliased types are semantically identical to the types they are aliased to. The debugger cannot distinguish between them, and there is no difference as far as function overloading is concerned. For example:

alias int myint;

void foo(int x) { . }
void foo(myint m) { . } // error, multiply defined function foo

Type aliases are equivalent to the C typedef.

Alias Declarations

A symbol can be declared as an alias of another symbol. For example:

import string;

alias string.strlen mylen;
 ...
int len = mylen("hello"); // actually calls string.strlen()

The following alias declarations are valid:

template Foo2(T) { alias T t; }
alias Foo2!(int) t1;
alias Foo2!(int).t t2;
alias t1.t t3;
alias t2 t4;

t1.t v1;  // v1 is type int
t2 v2;    // v2 is type int
t3 v3;    // v3 is type int
t4 v4;    // v4 is type int

Aliased symbols are useful as a shorthand for a long qualified symbol name, or as a way to redirect references from one symbol to another:

version (Win32)
{
    alias win32.foo myfoo;
}
version (linux)
{
    alias linux.bar myfoo;
}

Aliasing can be used to ‘import’ a symbol from an import into the current scope:

alias string.strlen strlen;

Aliases can also ‘import’ a set of overloaded functions, that can be overloaded with functions in the current scope:

class A {
    int foo(int a) { return 1; }
}

class B : A {
    int foo( int a, uint b ) { return 2; }
}

class C : B {
    int foo( int a ) { return 3; }
    alias B.foo foo;
}

class D : C  {
}

void test()
{
    D b = new D();
    int i;

    i = b.foo(1, 2u);   // calls B.foo
    i = b.foo(1);       // calls C.foo
}

Note: Type aliases can sometimes look indistinguishable from alias declarations:

alias foo.bar abc; // is it a type or a symbol?

The distinction is made in the semantic analysis pass.

Aliases cannot be used for expressions:

struct S { static int i; }
S s;

alias s.i a; // illegal, s.i is an expression
alias S.i b; // ok
b = 4;       // sets S.i to 4

Extern Declarations

Variable declarations with the storage class extern are not allocated storage within the module. They must be defined in some other object file with a matching name which is then linked in. The primary usefulness of this is to connect with global variable declarations in C files.

typeof

Typeof:
    typeof ( Expression )
    typeof ( return )

Typeof is a way to specify a type based on the type of an expression. For example:

void func(int i) {
 typeof(i) j;       // j is of type int
 typeof(3 + 6.0) x; // x is of type double
 typeof(1)* p;      // p is of type pointer to int
 int[typeof(p)] a;  // a is of type int[int*]

 writefln("%d", typeof('c').sizeof); // prints 1
 double c = cast(typeof(1.0))j; // cast j to double
}

Expression is not evaluated, just the type of it is generated:

void func() {
 int i = 1;
 typeof(++i) j; // j is declared to be an int, i is not incremented
 writefln("%d", i);  // prints 1
}

There are two special cases:

  1. typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function.
  2. Analogously, typeof(super) will generate the type of what super would be in a non-static member function.

class A { }

class B : A {
 typeof(this) x;  // x is declared to be a B
 typeof(super) y; // y is declared to be an A
}

struct C {
 typeof(this) z;  // z is declared to be a C*
 typeof(super) q; // error, no super struct for C
}

typeof(this) r;   // error, no enclosing struct or class

Where Typeof is most useful is in writing generic template code.

Void Initializations

VoidInitializer:
    void

Normally, variables are initialized either with an explicit Initializer or are set to the default value for the type of the variable. If the Initializer is void, however, the variable is not initialized. If its value is used before it is set, undefined program behavior will result.

void foo() {
 int x = void;
 writefln(x);  // will print garbage
}

Therefore, one should only use void initializers as a last resort when optimizing critical code.

Global and Static Initializers

The Initializer for a global or static variable must be evaluatable at compile time. Whether some pointers can be initialized with the addresses of other functions or data is implementation defined. Runtime initialization can be done with static constructors.


Types

Last update Sun Dec 30 20:34:42 2012

Types

Basic Data Types

Basic Data Types
Keyword | Description | Default Initializer (.init)
void | no type | -
bool | boolean value | false
byte | signed 8 bits | 0
ubyte | unsigned 8 bits | 0
short | signed 16 bits | 0
ushort | unsigned 16 bits | 0
int | signed 32 bits | 0
uint | unsigned 32 bits | 0
long | signed 64 bits | 0L
ulong | unsigned 64 bits | 0L
cent | signed 128 bits (reserved for future use) | 0
ucent | unsigned 128 bits (reserved for future use) | 0
float | 32 bit floating point | float.nan
double | 64 bit floating point | double.nan
real | largest hardware implemented floating point size (Implementation Note: 80 bits for x86 CPUs) or double size, whichever is larger | real.nan
ifloat | imaginary float | float.nan * 1.0i
idouble | imaginary double | double.nan * 1.0i
ireal | imaginary real | real.nan * 1.0i
cfloat | a complex number of two float values | float.nan + float.nan * 1.0i
cdouble | complex double | double.nan + double.nan * 1.0i
creal | complex real | real.nan + real.nan * 1.0i
char | unsigned 8 bit UTF-8 | 0xFF
wchar | unsigned 16 bit UTF-16 | 0xFFFF
dchar | unsigned 32 bit UTF-32 | 0x0000FFFF

Derived Data Types

  • pointer
  • array
  • associative array
  • function
  • delegate

Strings are a special case of arrays.

User Defined Types

  • alias
  • enum
  • struct
  • union
  • class
  • typedef

Base Types

The base type of an enum is the type it is based on:

enum E : T { ... }  // T is the base type of E

The base type of a typedef is the type it is formed from:

typedef T U;  // T is the base type of U

Pointer Conversions

Casting pointers to non-pointers and vice versa is allowed in D, however, do not do this for any pointers that point to data allocated by the garbage collector.

Implicit Conversions

Implicit conversions are used to automatically convert types as required.

A typedef or enum can be implicitly converted to its base type, but going the other way requires an explicit conversion. A literal can be implicitly converted to a typedef. For example:

int i;
typedef int myint;
myint m;
i = m;             // OK
m = i;             // error
m = cast(myint)i;  // OK
m = 3;             // OK
enum Foo { E }
Foo f;
i = f;           // OK
f = i;           // error
f = cast(Foo)i;  // OK
f = 0;           // error
f = Foo.E;       // OK

Integer Promotions

Integer Promotions are conversions of the following types:

Integer Promotions
from | to
bool | int
byte | int
ubyte | int
short | int
ushort | int
char | int
wchar | int
dchar | uint

If a typedef or enum has as a base type one of the types in the left column, it is converted to the type in the right column.

Usual Arithmetic Conversions

The usual arithmetic conversions convert operands of binary operators to a common type. The operands must already be of arithmetic types. The following rules are applied in order, looking at the base type:

  1. If either operand is real, the other operand is converted to real.
  2. Else if either operand is double, the other operand is converted to double.
  3. Else if either operand is float, the other operand is converted to float.
  4. Else the integer promotions are done on each operand, followed by:
    1. If both are the same type, no more conversions are done.
    2. If both are signed or both are unsigned, the smaller type is converted to the larger.
    3. If the signed type is larger than the unsigned type, the unsigned type is converted to the signed type.
    4. The signed type is converted to the unsigned type.

If one or both of the operand types is an enum or typedef after undergoing the above conversions, the result type is:

  1. If the operands are the same type, the result will be the that type.
  2. If one operand is an enum or typedef and the other is the base type of that typedef or enum, the result is the base type.
  3. If the two operands are different typedefs or enums, the result is the closest base type common to both. A base type being closer means there is a shorter sequence of conversions to base type to get there from the original type.

Integer values cannot be implicitly converted to another type that cannot represent the integer bit pattern after integral promotion. For example:

ubyte  u1 = cast(byte)-1;  // error, -1 cannot be represented in a ubyte
ushort u2 = cast(short)-1; // error, -1 cannot be represented in a ushort
uint   u3 = cast(int)-1;   // ok, -1 can be represented in a uint
ulong  u4 = cast(long)-1; // ok, -1 can be represented in a ulong

Floating point types cannot be implicitly converted to integral types.

Complex floating point types cannot be implicitly converted to non-complex floating point types.

Imaginary floating point types cannot be implicitly converted to float, double, or real types. Float, double, or real types cannot be implicitly converted to imaginary floating point types.

bool

The bool type is a 1 byte size type that can only hold the value true or false. The only operators that can accept operands of type bool are: & | ^ &= |= ^= ! && || ?:. A bool value can be implicitly converted to any integral type, with false becoming 0 and true becoming 1. The numeric literals 0 and 1 can be implicitly converted to the bool values false and true, respectively. Casting an expression to bool means testing for 0 or !=0 for arithmetic types, and null or !=null for pointers or references.

Delegates

There are no pointers-to-members in D, but a more useful concept called delegates are supported. Delegates are an aggregate of two pieces of data: an object reference and a pointer to a non-static member function, or a pointer to a closure and a pointer to a nested function. The object reference forms the this pointer when the function is called.

Delegates are declared similarly to function pointers, except that the keyword delegate takes the place of (*), and the identifier occurs afterwards:

int function(int) fp; // fp is pointer to a function
int delegate(int) dg; // dg is a delegate to a function

The C style syntax for declaring pointers to functions is also supported:

int (*fp)(int);  // fp is pointer to a function

A delegate is initialized analogously to function pointers:

int func(int);
fp = &func;   // fp points to func

class OB {
    int member(int);
}
OB o;
dg = &o.member; // dg is a delegate to object o and
                // member function member

Delegates cannot be initialized with static member functions or non-member functions.

Delegates are called analogously to function pointers:

fp(3);   // call func(3)
dg(3);   // call o.member(3)

The equivalent of member function pointers can be constructed using anonymous lambda functions:

class C {
  int a;
  int foo(int i) { return i + a; }
}

// mfp is the member function pointer
auto mfp = function(C self, int i) { return self.foo(i); };
auto c = new C();  // create an instance of C
mfp(c, 1);  // and call c.foo(1)

size_t And ptrdiff_t

size_t is an alias to one of the unsigned integral basic types, and represents a type that is large enough to represent an offset into all addressible memory.

ptrdiff_t is an alias to the signed basic type the same size as size_t.


Properties

Last update Sun Dec 30 20:34:42 2012

Properties

Every type and expression has properties that can be queried:

Property Examples
Expression | Value
int.sizeof | yields 4
float.nan | yields the floating point nan (Not A Number) value
(float).nan | yields the floating point nan value
(3).sizeof | yields 4 (because 3 is an int)
2.sizeof | syntax error, since "2." is a floating point number
int.init | default initializer for int's
int.mangleof | yields the string "i"
int.stringof | yields the string "int"
(1+2).stringof | yields the string "1 + 2"

Properties for All Types
Property | Description
.init | initializer
.sizeof | size in bytes (equivalent to C's sizeof(type))
.alignof | alignment size
.mangleof | string representing the ‘mangled’ representation of the type
.stringof | string representing the source representation of the type

Properties for Integral Types
Property | Description
.init | initializer (0)
.max | maximum value
.min | minimum value

Properties for Floating Point Types
Property | Description
.init | initializer (NaN)
.infinity | infinity value
.nan | NaN value
.dig | number of decimal digits of precision
.epsilon | smallest increment to the value 1
.mant_dig | number of bits in mantissa
.max_10_exp | maximum int value such that 10max_10_exp is representable
.max_exp | maximum int value such that 2max_exp-1 is representable
.min_10_exp | minimum int value such that 10min_10_exp is representable as a normalized value
.min_exp | minimum int value such that 2min_exp-1 is representable as a normalized value
.max | largest representable value that's not infinity
.min | smallest representable normalized value that's not 0
.re | real part
.im | imaginary part

Properties for Class Types
Property | Description
.classinfo | Information about the dynamic type of the class

.init Property

.init produces a constant expression that is the default initializer. If applied to a type, it is the default initializer for that type. If applied to a variable or field, it is the default initializer for that variable or field's type. For example:

int a;
int b = 1;
typedef int t = 2;
t c;
t d = cast(t)3;

int.init // is 0
a.init   // is 0
b.init   // is 0
t.init   // is 2
c.init   // is 2
d.init   // is 2

struct Foo {
  int a;
  int b = 7;
}

Foo.init.a  // is 0
Foo.init.b  // is 7

.stringof Property

.stringof produces a constant string that is the source representation of its prefix. If applied to a type, it is the string for that type. If applied to an expression, it is the source representation of that expression. Semantic analysis is not done for that expression. For example:

module test;
import std.stdio;

struct Foo { }

enum Enum { RED }

typedef int myint;

void main() {
  writeln((1+2).stringof);       // "1 + 2"
  writeln(Foo.stringof);         // "Foo"
  writeln(test.Foo.stringof);    // "Foo"
  writeln(int.stringof);         // "int"
  writeln((int*[5][]).stringof); // "int*[5u][]"
  writeln(Enum.RED.stringof);    // "cast(enum)0"
  writeln(test.myint.stringof);  // "myint"
  writeln((5).stringof);         // "5"
}

.sizeof Property

e.sizeof gives the size in bytes of the expression e.

When getting the size of a member, it is not necessary for there to be a this object:

struct S {
  int a;
  static int foo() {
    return a.sizeof; // returns 4
  }
}

void test() {
  int x = S.a.sizeof; // sets x to 4
}

.sizeof applied to a class object returns the size of the class reference, not the class instantiation.

.alignof Property

.alignof gives the aligned size of an expression or type. For example, an aligned size of 1 means that it is aligned on a byte boundary, 4 means it is aligned on a 32 bit boundary.

.classinfo Property

.classinfo provides information about the dynamic type of a class object. It returns a reference to type object.ClassInfo.

.classinfo applied to an interface gives the information for the interface, not the class it might be an instance of.

User Defined Properties

Properties are functions that can be syntactically treated as if they were fields or variables. Properties can be read from or written to. A property is read by calling a methhod or function with no arguments; a property is written by calling a method or function with its argument being the value it is set to.

A simple property would be:

struct Foo
{
  int data() { return m_data; }	// read property

  int data(int value) { return m_data = value; } // write property

private:
  int m_data;
}

To use it:

int test() {
  Foo f;

  f.data = 3;        // same as f.data(3);
  return f.data + 3; // same as return f.data() + 3;
}

The absence of a read method means that the property is write-only. The absence of a write method means that the property is read-only. Multiple write methods can exist; the correct one is selected using the usual function overloading rules.

In all the other respects, these methods are like any other methods. They can be static, have different linkages, be overloaded with methods with multiple parameters, have their address taken, etc.

Note: Properties cannot be the lvalue of an op=, ++, or -- operator.

The built in properties .sizeof, .alignof, and .mangleof may not be declared as fields or methods in structs, unions, classes or enums.

If a .property is applied to a user-defined property, the .property is applied to the result of the function call.


Attributes

Last update Sun Dec 30 20:34:42 2012

Attributes

AttributeSpecifier:
    Attribute :
    Attribute DeclarationBlock

Attribute:
    LinkageAttribute
    AlignAttribute
    Pragma
    deprecated
    ProtectionAttribute
    static
    extern
    final
    synchronized
    override
    abstract
    const
    auto
    scope

DeclarationBlock:
    DeclDef
    { DeclDefsopt }

Attributes are a way to modify one or more declarations. The general forms are:

attribute declaration; // affects the declaration

attribute:     // affects all declarations until the end of
               // the current scope
  declaration;
  declaration;
  ...

attribute {    // affects all declarations in the block
  declaration;
  declaration;
  ...
}

Linkage Attribute

LinkageAttribute:
    extern ( LinkageType )

LinkageType:
    C
    C++
    D
    Windows
    Pascal
    System

D provides an easy way to call C functions and operating system API functions, as compatibility with both is essential. The LinkageType is case sensitive, and is meant to be extensible by the implementation (they are not keywords). C and D must be supplied, the others are what makes sense for the implementation. C++ is reserved for future use. System is the same as Windows on Windows platforms, and C on other platforms. Implementation Note: for Win32 platforms, Windows and Pascal should exist.

C function calling conventions are specified by:

extern (C):
  int foo(); // call foo() with C conventions

D conventions are:

extern (D):

or:

extern:

Windows API conventions are:

extern (Windows):
  void *VirtualAlloc(
    void *lpAddress,
    uint dwSize,
    uint flAllocationType,
    uint flProtect
    );

Align Attribute

AlignAttribute:
    align
    align ( IntegerLiteral )

Specifies the alignment of struct members. align by itself sets it to the default, which matches the default member alignment of the companion C compiler. Integer specifies the alignment which matches the behavior of the companion C compiler when non-default alignments are used.

Matching the behavior of the companion C compiler can have some surprising results, such as the following for Digital Mars C++:

struct S {
  align(4) byte a; // placed at offset 0
  align(4) byte b; // placed at offset 1
}

AlignAttribute is meant for C ABI compatiblity, which is not the same thing as binary compatibility across diverse platforms. For that, use packed structs:

align (1) struct S {
  byte a;     // placed at offset 0
  byte[3] filler1;
  byte b;     // placed at offset 4
  byte[3] filler2;
}

A value of 1 means that no alignment is done; members are packed together.

Do not align references or pointers that were allocated using NewExpression on boundaries that are not a multiple of size_t. The garbage collector assumes that pointers and references to gc allocated objects will be on size_t byte boundaries. If they are not, undefined behavior will result.

AlignAttribute is ignored when applied to declarations that are not struct members. Whether it applies to class members or not is implementation defined.

The AlignAttribute is reset to the default when entering a struct, union, class, or function scope, and restored when exiting that scope. It is not inherited from a base class.

Deprecated Attribute

It is often necessary to deprecate a feature in a library, yet retain it for backwards compatibility. Such declarations can be marked as deprecated, which means that the compiler can be set to produce an error if any code refers to deprecated declarations:

deprecated
{
  void oldFoo();
}

Implementation Note: The compiler should have a switch specifying if deprecated declarations should be compiled with out complaint or not.

Protection Attribute

ProtectionAttribute:
    private
    package
    protected
    public
    export

Protection is an attribute that is one of private, package, protected, public or export.

Private means that only members of the enclosing class can access the member, or members and functions in the same module as the enclosing class. Private members cannot be overridden. Private module members are equivalent to static declarations in C programs.

Package extends private so that package members can be accessed from code in other modules that are in the same package. This applies to the innermost package only, if a module is in nested packages.

Protected means that only members of the enclosing class or any classes derived from that class, or members and functions in the same module as the enclosing class, can access the member. If accessing a protected instance member through a derived class member function, that member can only be accessed for the object instance which can be implicitly cast to the same type as ‘this’. Protected module members are illegal.

Public means that any code within the executable can access the member.

Export means that any code outside the executable can access the member. Export is analogous to exporting definitions from a DLL.

Protection does not participate in name lookup. In particular, if two symbols with the same name are in scope, and that name is used unqualified then the lookup will be ambiguous, even if one of the symbols is inaccessible due to protection. For example:

module A;
private class Foo {}

module B;
public class Foo {}

import A;
import B;

Foo f1; // error, could be either A.Foo or B.Foo
B.Foo f2; // ok

Const Attribute

The const attribute declares constants that can be evaluated at compile time. For example:

const int foo = 7;

const {
  double bar = foo + 6;
}

A const declaration without an initializer must be initialized in a constructor (for class fields) or in a static constructor (for static class members, or module variable declarations).

const int x;
const int y;

static this()
{
  x = 3;   // ok
  // error: y not initialized
}

void foo()
{
  x = 4; // error, x is const and not in static constructor
}

class C
{
  const int a;
  const int b;
  static const int c;
  static const int d;

  this() {
    a = 3;      // ok
    a = 4;      // ok, multiple initialization allowed
    C p = this;
    p.a = 4;    // error, only members of this instance
    c = 5;      // error, should initialize in static constructor
    // error, b is not initialized
  }

  this(int x) {
    this();      // ok, forwarding constructor
  }

  static this() {
    c = 3;       // ok
    // error, d is not initialized
  }
}

It is not an error to have const module variable declarations without initializers if there is no constructor. This is to support the practice of having modules serve only as declarations that are not linked in, the implementation of it will be in another module that is linked in.

Override Attribute

The override attribute applies to virtual functions. It means that the function must override a function with the same name and parameters in a base class. The override attribute is useful for catching errors when a base class's member function gets its parameters changed, and all derived classes need to have their overriding functions updated.

class Foo {
  int bar();
  int abc(int x);
}

class Foo2 : Foo {
  override {
    int bar(char c); // error, no bar(char) in Foo
    int abc(int x);  // ok
  }
}

Static Attribute

The static attribute applies to functions and data. It means that the declaration does not apply to a particular instance of an object, but to the type of the object. In other words, it means there is no this reference. static is ignored when applied to other declarations.

class Foo {
  static int bar() { return 6; }
  int foobar() { return 7; }
}

...

Foo f = new Foo;
Foo.bar();      // produces 6
Foo.foobar();   // error, no instance of Foo
f.bar();        // produces 6;
f.foobar();     // produces 7;

Static functions are never virtual.

Static data has only one instance for the entire program, not once per object.

Static does not have the additional C meaning of being local to a file. Use the private attribute in D to achieve that. For example:

module foo;
int x = 3;         // x is global
private int y = 4; // y is local to module foo

Auto Attribute

The auto attribute is used when there are no other attributes and type inference is desired.

auto i = 6.8;   // declare i as a double

Scope Attribute

The scope attribute is used for local variables and for class declarations. For class declarations, the scope attribute creates a scope class. For local declarations, scope implements the RAII (Resource Acquisition Is Initialization) protocol. This means that the destructor for an object is automatically called when the reference to it goes out of scope. The destructor is called even if the scope is exited via a thrown exception, thus scope is used to guarantee cleanup.

If there is more than one scope variable going out of scope at the same point, then the destructors are called in the reverse order that the variables were constructed.

scope cannot be applied to globals, statics, data members, ref or out parameters. Arrays of scopes are not allowed, and scope function return values are not allowed. Assignment to a scope, other than initialization, is not allowed. Rationale: These restrictions may get relaxed in the future if a compelling reason to appears.

Abstract Attribute

If a class is abstract, it cannot be instantiated directly. It can only be instantiated as a base class of another, non-abstract, class.

Classes become abstract if they are defined within an abstract attribute, or if any of the virtual member functions within it are declared as abstract.

Non-virtual functions cannot be declared as abstract.

Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide ‘base class functionality.’


Pragmas

Last update Sun Dec 30 20:34:42 2012

Pragmas

Pragma:
    pragma ( Identifier )
    pragma ( Identifier , ArgumentList )

Pragmas are a way to pass special information to the compiler and to add vendor specific extensions to D. Pragmas can be used by themselves terminated with a ‘;’, they can influence a statement, a block of statements, a declaration, or a block of declarations.

Pragmas can appear as either declarations, Pragma DeclarationBlock, or as statements, PragmaStatement.

pragma(ident);        // just by itself

pragma(ident) declaration; // influence one declaration

pragma(ident): // influence subsequent declarations
    declaration;
    declaration;

pragma(ident) { // influence block of declarations
    declaration;
    declaration;
}

pragma(ident) statement; // influence one statement

pragma(ident) { // influence block of statements
    statement;
    statement;
}

The kind of pragma it is is determined by the Identifier. ExpressionList is a comma-separated list of AssignExpressions. The AssignExpressions must be parsable as expressions, but what they mean semantically is up to the individual pragma semantics.

Predefined Pragmas

All implementations must support these, even if by just ignoring them:

msg
Prints a message to the standard error stream while compiling, the AssignExpressions must be string literals:
pragma(msg, "compiling...");
lib
Inserts a directive in the object file to link in the library specified by the AssignExpression. The AssignExpressions must be a string literal:
pragma(lib, "foo.lib");

Vendor Specific Pragmas

Vendor specific pragma Identifiers can be defined if they are prefixed by the vendor's trademarked name, in a similar manner to version identifiers:

pragma(DigitalMars_funky_extension) { ... }

Compilers must diagnose an error for unrecognized Pragmas, even if they are vendor specific ones. This implies that vendor specific pragmas should be wrapped in version statements:

version (DigitalMars)
{
    pragma(DigitalMars_funky_extension)
    { ... }
}


Expressions

Last update Sun Dec 30 20:34:42 2012

Expressions

C and C++ programmers will find the D expressions very familiar, with a few interesting additions.

Expressions are used to compute values with a resulting type. These values can then be assigned, tested, or ignored. Expressions can also have side effects.

Order Of Evaluation

The following binary expressions are evaluated in strictly left-to-right order:

CommaExpression, OrOrExpression, AndAndExpression

The following binary expressions are evaluated in an implementation-defined order:

AssignExpression, OrExpression, XorExpression, AndExpression, CmpExpression, ShiftExpression, AddExpression, CatExpression, MulExpression, function parameters

It is an error to depend on order of evaluation when it is not specified. For example, the following are illegal:

i = i++;
c = a + (a = b);
func(++i, ++i);

If the compiler can determine that the result of an expression is illegally dependent on the order of evaluation, it can issue an error (but is not required to). The ability to detect these kinds of errors is a quality of implementation issue.

Expressions

Expression:
    CommaExpression

CommaExpression:
    AssignExpression
    AssignExpression , CommaExpression
The left operand of the , is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand.

Assign Expressions

AssignExpression:
    ConditionalExpression
    ConditionalExpression = AssignExpression
    ConditionalExpression += AssignExpression
    ConditionalExpression -= AssignExpression
    ConditionalExpression *= AssignExpression
    ConditionalExpression /= AssignExpression
    ConditionalExpression %= AssignExpression
    ConditionalExpression &= AssignExpression
    ConditionalExpression |= AssignExpression
    ConditionalExpression ^= AssignExpression
    ConditionalExpression ~= AssignExpression
    ConditionalExpression <<= AssignExpression
    ConditionalExpression >>= AssignExpression
    ConditionalExpression >>>= AssignExpression
The right operand is implicitly converted to the type of the left operand, and assigned to it. The result type is the type of the lvalue, and the result value is the value of the lvalue after the assignment.

The left operand must be an lvalue.

Assignment Operator Expressions

Assignment operator expressions, such as:
a op= b
are semantically equivalent to:
a = cast(typeof(a))(a op b)

except that:

  • operand a is only evaluated once
  • overloading op uses a different function than overloading op= does
  • the left operand of >>>= does not undergo integral promotions before shifting

Conditional Expressions

ConditionalExpression:
    OrOrExpression
    OrOrExpression ? Expression : ConditionalExpression
The first expression is converted to bool, and is evaluated. If it is true, then the second expression is evaluated, and its result is the result of the conditional expression. If it is false, then the third expression is evaluated, and its result is the result of the conditional expression. If either the second or third expressions are of type void, then the resulting type is void. Otherwise, the second and third expressions are implicitly converted to a common type which becomes the result type of the conditional expression.

OrOr Expressions

OrOrExpression:
    AndAndExpression
    OrOrExpression || AndAndExpression
The result type of an OrOrExpression is bool, unless the right operand has type void, when the result is type void.

The OrOrExpression evaluates its left operand. If the left operand, converted to type bool, evaluates to true, then the right operand is not evaluated. If the result type of the OrOrExpression is bool then the result of the expression is true. If the left operand is false, then the right operand is evaluated. If the result type of the OrOrExpression is bool then the result of the expression is the right operand converted to type bool.

AndAnd Expressions

AndAndExpression:
    OrExpression
    AndAndExpression && OrExpression

The result type of an AndAndExpression is bool, unless the right operand has type void, when the result is type void.

The AndAndExpression evaluates its left operand.

If the left operand, converted to type bool, evaluates to false, then the right operand is not evaluated. If the result type of the AndAndExpression is bool then the result of the expression is false.

If the left operand is true, then the right operand is evaluated. If the result type of the AndAndExpression is bool then the result of the expression is the right operand converted to type bool.

Bitwise Expressions

Bit wise expressions perform a bitwise operation on their operands. Their operands must be integral types. First, the default integral promotions are done. Then, the bitwise operation is done.

Or Expressions

OrExpression:
    XorExpression
    OrExpression | XorExpression
The operands are OR'd together.

Xor Expressions

XorExpression:
    AndExpression
    XorExpression ^ AndExpression
The operands are XOR'd together.

And Expressions

AndExpression:
    CmpExpression
    AndExpression & CmpExpression
The operands are AND'd together.

Compare Expressions

CmpExpression:
    ShiftExpression
    EqualExpression
    IdentityExpression
    RelExpression
    InExpression

Equality Expressions

EqualExpression:
    ShiftExpression == ShiftExpression
    ShiftExpression != ShiftExpression
Equality expressions compare the two operands for equality (==) or inequality (!=). The type of the result is bool. The operands go through the usual conversions to bring them to a common type before comparison.

If they are integral values or pointers, equality is defined as the bit pattern of the type matches exactly. Equality for struct objects means the bit patterns of the objects match exactly (the existence of alignment holes in the objects is accounted for, usually by setting them all to 0 upon initialization). Equality for floating point types is more complicated. -0 and +0 compare as equal. If either or both operands are NAN, then both the == returns false and != returns true. Otherwise, the bit patterns are compared for equality.

For complex numbers, equality is defined as equivalent to:

x.re == y.re && x.im == y.im
and inequality is defined as equivalent to:
x.re != y.re || x.im != y.im

For class and struct objects, the expression (a == b) is rewritten as a.opEquals(b), and (a != b) is rewritten as !a.opEquals(b).

For class objects, the == and != operators compare the contents of the objects. Therefore, comparing against null is invalid, as null has no contents. Use the is and !is operators instead.

class C;
C c;
if (c == null)  // error
  ...
if (c is null)  // ok
  ...

For static and dynamic arrays, equality is defined as the lengths of the arrays matching, and all the elements are equal.

Identity Expressions

IdentityExpression:
    ShiftExpression is ShiftExpression
    ShiftExpression !is ShiftExpression

The is compares for identity. To compare for not identity, use e1 !is e2. The type of the result is bool. The operands go through the usual conversions to bring them to a common type before comparison.

For class objects, identity is defined as the object references are for the same object. Null class objects can be compared with is.

For struct objects, identity is defined as the bits in the struct being identical.

For static and dynamic arrays, identity is defined as referring to the same array elements and the same number of elements.

For other operand types, identity is defined as being the same as equality.

The identity operator is cannot be overloaded.

Relational Expressions

RelExpression:
    ShiftExpression < ShiftExpression
    ShiftExpression <= ShiftExpression
    ShiftExpression > ShiftExpression
    ShiftExpression >= ShiftExpression
    ShiftExpression !<>= ShiftExpression
    ShiftExpression !<> ShiftExpression
    ShiftExpression <> ShiftExpression
    ShiftExpression <>= ShiftExpression
    ShiftExpression !> ShiftExpression
    ShiftExpression !>= ShiftExpression
    ShiftExpression !< ShiftExpression
    ShiftExpression !<= ShiftExpression
First, the integral promotions are done on the operands. The result type of a relational expression is bool.

For class objects, the result of Object.opCmp() forms the left operand, and 0 forms the right operand. The result of the relational expression (o1 op o2) is:

(o1.opCmp(o2) op 0)
It is an error to compare objects if one is null.

For static and dynamic arrays, the result of the relational op is the result of the operator applied to the first non-equal element of the array. If two arrays compare equal, but are of different lengths, the shorter array compares as "less" than the longer array.

Integer comparisons

Integer comparisons happen when both operands are integral types.

Integer comparison operators
Operator | Relation
< | less
> | greater
<= | less or equal
>= | greater or equal
== | equal
!= | not equal

It is an error to have one operand be signed and the other unsigned for a <, <=, > or >= expression. Use casts to make both operands signed or both operands unsigned.

Floating point comparisons

If one or both operands are floating point, then a floating point comparison is performed.

Useful floating point operations must take into account NAN values. In particular, a relational operator can have NAN operands. The result of a relational operation on float values is less, greater, equal, or unordered (unordered means either or both of the operands is a NAN). That means there are 14 possible comparison conditions to test for:

Floating point comparison operators
Operator | Greater Than | Less Than | Equal | Unordered | Exception | Relation
== | F | F | T | F | no | equal
!= | T | T | F | T | no | unordered, less, or greater
> | T | F | F | F | yes | greater
>= | T | F | T | F | yes | greater or equal
< | F | T | F | F | yes | less
<= | F | T | T | F | yes | less or equal
!<>= | F | F | F | T | no | unordered
<> | T | T | F | F | yes | less or greater
<>= | T | T | T | F | yes | less, equal, or greater
!<= | T | F | F | T | no | unordered or greater
!< | T | F | T | T | no | unordered, greater, or equal
!>= | F | T | F | T | no | unordered or less
!> | F | T | T | T | no | unordered, less, or equal
!<> | F | F | T | T | no | unordered or equal

Notes:

  1. For floating point comparison operators, (a !op b) is not the same as !(a op b).
  2. "Unordered" means one or both of the operands is a NAN.
  3. "Exception" means the Invalid Exception is raised if one of the operands is a NAN. It does not mean an exception is thrown. The Invalid Exception can be checked using the functions in std.c.fenv.

Class comparisons

For class objects, the relational operators compare the contents of the objects. Therefore, comparing against null is invalid, as null has no contents.

class C;
C c;
if (c < null)  // error
  ...

In Expressions

InExpression:
    ShiftExpression in ShiftExpression

An associative array can be tested to see if an element is in the array:

int foo[char[]];
...
if ("hello" in foo)
    ...

The in expression has the same precedence as the relational expressions <, <=, etc. The return value of the InExpression is null if the element is not in the array; if it is in the array it is a pointer to the element.

Shift Expressions

ShiftExpression:
    AddExpression
    ShiftExpression << AddExpression
    ShiftExpression >> AddExpression
    ShiftExpression >>> AddExpression

The operands must be integral types, and undergo the usual integral promotions. The result type is the type of the left operand after the promotions. The result value is the result of shifting the bits by the right operand's value.

<< is a left shift. >> is a signed right shift. >>> is an unsigned right shift.

It's illegal to shift by the same or more bits than the size of the quantity being shifted:

int c;
c << 33;        // error

Add Expressions

AddExpression:
    MulExpression
    AddExpression + MulExpression
    AddExpression - MulExpression
    CatExpression

If the operands are of integral types, they undergo integral promotions, and then are brought to a common type using the usual arithmetic conversions.

If either operand is a floating point type, the other is implicitly converted to floating point and they are brought to a common type via the usual arithmetic conversions.

If the operator is + or -, and the first operand is a pointer, and the second is an integral type, the resulting type is the type of the first operand, and the resulting value is the pointer plus (or minus) the second operand multiplied by the size of the type pointed to by the first operand.

If the second operand is a pointer, and the first is an integral type, and the operator is +, the operands are reversed and the pointer arithmetic just described is applied.

If both operands are pointers, and the operator is +, then it is illegal. For -, the pointers are subtracted and the result is divided by the size of the type pointed to by the operands. It is an error if the pointers point to different types.

Add expressions for floating point operands are not associative.

Cat Expressions

CatExpression:
    AddExpression ~ MulExpression

A CatExpression concatenates arrays, producing a dynmaic array with the result. The arrays must be arrays of the same element type. If one operand is an array and the other is of that array's element type, that element is converted to an array of length 1 of that element, and then the concatenation is performed.

Mul Expressions

MulExpression:
    UnaryExpression
    MulExpression * UnaryExpression
    MulExpression / UnaryExpression
    MulExpression % UnaryExpression

The operands must be arithmetic types. They undergo integral promotions, and then are brought to a common type using the usual arithmetic conversions.

For integral operands, the *, /, and % correspond to multiply, divide, and modulus operations. For multiply, overflows are ignored and simply chopped to fit into the integral type.

For integral operands of the / and % operators, the quotient rounds towards zero and the remainder has the same sign as the dividend. If the divisor is zero, an Exception is thrown.

For floating point operands, the * and / operations correspond to the IEEE 754 floating point equivalents. % is not the same as the IEEE 754 remainder. For example, 15.0 % 10.0 == 5.0, whereas for IEEE 754, remainder(15.0,10.0) == -5.0.

Mul expressions for floating point operands are not associative.

Unary Expressions

UnaryExpression:
    & UnaryExpression
    ++ UnaryExpression
    -- UnaryExpression
    * UnaryExpression
    - UnaryExpression
    + UnaryExpression
    ! UnaryExpression
    ComplementExpression
    ( Type ) . Identifier
    NewExpression
    DeleteExpression
    CastExpression
    PostfixExpression

Complement Expressions

ComplementExpression:
    ~ UnaryExpression

ComplementExpressions work on integral types (except bool). All the bits in the value are complemented.

Note: unlike in C and C++, the usual integral promotions are not performed prior to the complement operation.

New Expressions

NewExpression:
    new AllocatorArgumentsopt Type [ AssignExpression ]
    new AllocatorArgumentsopt Type ( ArgumentList )
    new AllocatorArgumentsopt Type
    NewAnonClassExpression

AllocatorArguments:
    ( ArgumentListopt )

ArgumentList:
    AssignExpression
    AssignExpression , ArgumentList

NewExpressions are used to allocate memory on the garbage collected heap (default) or using a class or struct specific allocator.

To allocate multidimensional arrays, the declaration reads in the same order as the prefix array declaration order.

char[][] foo;   // dynamic array of strings
...
foo = new char[][30]; // allocate array of 30 strings

The above allocation can also be written as:

foo = new char[][](30); // allocate array of 30 strings

To allocate the nested arrays, multiple arguments can be used:

int[][][] bar;
...
bar = new int[][][](5,20,30);

Which is equivalent to:

bar = new int[][][5];
foreach (ref a; bar)
{
  a = new int[][20];
  foreach (ref b; a)
  {
    b = new int[30];
  }
}

If there is a new ( ArgumentList ), then those arguments are passed to the class or struct specific allocator function after the size argument.

If a NewExpression is used as an initializer for a function local variable with scope storage class, and the ArgumentList to new is empty, then the instance is allocated on the stack rather than the heap or using the class specific allocator.

Delete Expressions

DeleteExpression:
    delete UnaryExpression

If the UnaryExpression is a class object reference, and there is a destructor for that class, the destructor is called for that object instance.

Next, if the UnaryExpression is a class object reference, or a pointer to a struct instance, and the class or struct has overloaded operator delete, then that operator delete is called for that class object instance or struct instance.

Otherwise, the garbage collector is called to immediately free the memory allocated for the class instance or struct instance. If the garbage collector was not used to allocate the memory for the instance, undefined behavior will result.

If the UnaryExpression is a pointer or a dynamic array, the garbage collector is called to immediately release the memory. If the garbage collector was not used to allocate the memory for the instance, undefined behavior will result.

The pointer, dynamic array, or reference is set to null after the delete is performed. Any attempt to reference the data after the deletion via another reference to it will result in undefined behavior.

If UnaryExpression is a variable allocated on the stack, the class destructor (if any) is called for that instance. Neither the garbage collector nor any class deallocator is called.

Cast Expressions

CastExpression:
    cast ( Type ) UnaryExpression
    cast ( CastQual ) UnaryExpression
    cast ( ) UnaryExpression

CastQual:
    const
    const shared
    shared const
    inout
    inout shared
    shared inout
    immutable
    shared

A CastExpression converts the UnaryExpression to Type.

cast(foo) -p; // cast (-p) to type foo
(foo) - p;      // subtract p from foo

Any casting of a class reference to a derived class reference is done with a runtime check to make sure it really is a downcast. null is the result if it isn't. Note: This is equivalent to the behavior of the dynamic_cast operator in C++.

class A { ... }
class B : A { ... }

void test(A a, B b) {
  B bx = a;         // error, need cast
  B bx = cast(B) a; // bx is null if a is not a B
  A ax = b;         // no cast needed
  A ax = cast(A) b; // no runtime check needed for upcast
}

In order to determine if an object o is an instance of a class B use a cast:

if (cast(B) o)
{
  // o is an instance of B
}
else
{
  // o is not an instance of B
}

Casting a pointer type to and from a class type is done as a type paint (i.e. a reinterpret cast).

Casting a dynamic array to another dynamic array is done only if the array lengths multiplied by the element sizes match. The cast is done as a type paint, with the array length adjusted to match any change in element size. If there's not a match, a runtime error is generated.

import std.stdio;

int main() {
  byte[] a = [1,2,3];
  auto b = cast(int[])a; // runtime array cast misalignment

  int[] c = [1, 2, 3];
  auto d = cast(byte[])c; // ok
  // prints:
  // [1,0,0,0,2,0,0,0,3,0,0,0]
  writefln(d);
  return 0;
}

Casting a floating point literal from one type to another changes its type, but internally it is retained at full precision for the purposes of constant folding.

void test() {
  real a = 3.40483L;
  real b;
  b = 3.40483;     // literal is not truncated to double precision
  assert(a == b);
  assert(a == 3.40483);
  assert(a == 3.40483L);
  assert(a == 3.40483F);
  double d = 3.40483; // truncate literal when assigned to variable
  assert(d != a);     // so it is no longer the same
  const double x = 3.40483; // assignment to const is not
  assert(x == a);     // truncated if the initializer is visible
}

Casting a value v to a struct S, when value is not a struct of the same type, is equivalent to:

S(v)

Casting to a CastQual replaces the qualifiers to the type of the UnaryExpression.

shared int x;
assert(is(typeof(cast(const)x) == const int));

Casting with no Type or CastQual removes any top level const, immutable, shared or inout type modifiers from the type of the UnaryExpression.

shared int x;
assert(is(typeof(cast()x) == int));

Postfix Expressions

PostfixExpression:
    PrimaryExpression
    PostfixExpression . Identifier
    PostfixExpression . TemplateInstance
    PostfixExpression . NewExpression
    PostfixExpression ++
    PostfixExpression --
    PostfixExpression ( )
    PostfixExpression ( ArgumentList )
    IndexExpression
    SliceExpression

Index Expressions

IndexExpression:
    PostfixExpression [ ArgumentList ]

PostfixExpression is evaluated. If PostfixExpression is an expression of type static array or dynamic array, the symbol $ is set to be the the number of elements in the array. If PostfixExpression is an ExpressionTuple, the symbol $ is set to be the the number of elements in the tuple. A new declaration scope is created for the evaluation of the ArgumentList and $ appears in that scope only.

If PostfixExpression is an ExpressionTuple, then the ArgumentList must consist of only one argument, and that must be statically evaluatable to an integral constant. That integral constant n then selects the nth expression in the ExpressionTuple, which is the result of the IndexExpression. It is an error if n is out of bounds of the ExpressionTuple.

Slice Expressions

SliceExpression:
    PostfixExpression [ ]
    PostfixExpression [ AssignExpression .. AssignExpression ]

PostfixExpression is evaluated. if PostfixExpression is an expression of type static array or dynamic array, the variable length (and the special variable $ ) is declared and set to be the length of the array. A new declaration scope is created for the evaluation of the AssignExpression..AssignExpression and length (and $ ) appears in that scope only.

The first AssignExpression is taken to be the inclusive lower bound of the slice, and the second AssignExpression is the exclusive upper bound. The result of the expression is a slice of the PostfixExpression array.

If the [ ] form is used, the slice is of the entire array.

The type of the slice is a dynamic array of the element type of the PostfixExpression.

A SliceExpression is not a modifiable lvalue.

If PostfixExpression is an ExpressionTuple, then the result of the slice is a new ExpressionTuple formed from the upper and lower bounds, which must statically evaluate to integral constants. It is an error if those bounds are out of range.

Primary Expressions

PrimaryExpression:
    Identifier
    .Identifier
    TemplateInstance
    .TemplateInstance
    this
    super
    null
    true
    false
    $

    IntegerLiteral
    FloatLiteral
    CharacterLiteral
    StringLiterals
    ArrayLiteral
    AssocArrayLiteral
    Lambda
    FunctionLiteral
    AssertExpression
    MixinExpression
    ImportExpression
    BasicType . Identifier
    Typeof
    TypeidExpression
    IsExpression
    ( Expression )

.Identifier

Identifier is looked up at module scope, rather than the current lexically nested scope.

this

Within a non-static member function, this resolves to a reference to the object for which the function was called. If the object is an instance of a struct, this will be a pointer to that instance. If a member function is called with an explicit reference to typeof(this), a non-virtual call is made:

class A {
  char get() { return 'A'; }

  char foo() { return typeof(this).get(); }
  char bar() { return this.get(); }
}

class B : A {
  char get() { return 'B'; }
}

void main() {
  B b = new B();

  b.foo();  // returns 'A'
  b.bar();  // returns 'B'
}

Assignment to this is not allowed.

super

super is identical to this, except that it is cast to this's base class. It is an error if there is no base class. It is an error to use super within a struct member function. (Only class Object has no base class.) If a member function is called with an explicit reference to super, a non-virtual call is made.

Assignment to super is not allowed.

null

null represents the null value for pointers, pointers to functions, delegates, dynamic arrays, associative arrays, and class objects. If it has not already been cast to a type, it is given the type (void *) and it is an exact conversion to convert it to the null value for pointers, pointers to functions, delegates, etc. After it is cast to a type, such conversions are implicit, but no longer exact.

true, false

These are of type bool and when cast to another integral type become the values 1 and 0, respectively.

Character Literals

Character literals are single characters and resolve to one of type char, wchar, or dchar. If the literal is a \u escape sequence, it resolves to type wchar. If the literal is a \U escape sequence, it resolves to type dchar. Otherwise, it resolves to the type with the smallest size it will fit into.

String Literals

StringLiterals:
    StringLiteral
    StringLiterals StringLiteral

String literals can implicitly convert to any of the following types, they have equal weight:

char*
wchar*
dchar*
char[]
wchar[]
dchar[]

String literals have a 0 appended to them, which makes them easy to pass to C or C++ functions expecting a const char* string. The 0 is not included in the .length property of the string literal.

Array Literals

ArrayLiteral:
    [ ArgumentList ]

Array literals are a comma-separated list of AssignExpressions between square brackets [ and ]. The AssignExpressions form the elements of a static array, the length of the array is the number of elements. The type of the first element is taken to be the type of all the elements, and all elements are implicitly converted to that type. If that type is a static array, it is converted to a dynamic array.

[1,2,3];  // type is int[3], with elements 1, 2 and 3
[1u,2,3]; // type is uint[3], with elements 1u, 2u, and 3u

If any of the arguments in the ArgumentList are an ExpressionTuple, then the elements of the ExpressionTuple are inserted as arguments in place of the tuple.

Array literals are allocated on the memory managed heap. Thus, they can be returned safely from functions:

int[] foo() {
  return [1, 2, 3];
}

When array literals are cast to another array type, each element of the array is cast to the new element type. When arrays that are not literals are cast, the array is reinterpreted as the new type, and the length is recomputed:

import std.stdio;

void main() {
  // cast array literal
  const short[] ct = cast(short[]) [cast(byte)1, 1];
  writeln(ct);  // writes [1, 1]

  // cast other array expression
  short[] rt = cast(short[]) [cast(byte)1, cast(byte)1].dup;
  writeln(rt);  // writes [257]
}

Associative Array Literals

AssocArrayLiteral:
    [ KeyValuePairs ]

KeyValuePairs:
    KeyValuePair
    KeyValuePair , KeyValuePairs

KeyValuePair:
    KeyExpression : ValueExpression

KeyExpression:
    AssignExpression

ValueExpression:
    AssignExpression

Associative array literals are a comma-separated list of key:value pairs between square brackets [ and ]. The list cannot be empty. The type of the first key is taken to be the type of all the keys, and all subsequent keys are implicitly converted to that type. The type of the first value is taken to be the type of all the values, and all subsequent values are implicitly converted to that type. An AssocArrayLiteral cannot be used to statically initialize anything.

[21u:"he",38:"ho",2:"hi"]; // type is char[2][uint],
                           // with keys 21u, 38u and 2u
                           // and values "he", "ho", and "hi"

If any of the keys or values in the KeyValuePairs are an ExpressionTuple, then the elements of the ExpressionTuple are inserted as arguments in place of the tuple.

Lambdas

Lambda:
        Identifier => AssignExpression
        ParameterAttributes => AssignExpression

Lambdas are a shorthand syntax for FunctionLiterals. The first form is equivalent to:

delegate ( Identifier ) { return AssignExpression; }

And the second:

delegate ParameterAttributes { return AssignExpression; }

Function Literals

FunctionLiteral:
        function Typeopt ParameterAttributes opt FunctionBody
        delegate Typeopt ParameterAttributes opt FunctionBody
        ParameterAttributes FunctionBody
        FunctionBody

ParameterAttributes:
    Parameters
FunctionLiterals enable embedding anonymous functions and anonymous delegates directly into expressions. Type is the return type of the function or delegate, if omitted it is inferred from any ReturnStatements in the FunctionBody. ( ArgumentList ) forms the arguments to the function. If omitted it defaults to the empty argument list ( ). The type of a function literal is pointer to function or pointer to delegate. If the keywords function or delegate are omitted, it defaults to being a delegate.

For example:

int function(char c) fp; // declare pointer to a function

void test() {
  static int foo(char c) { return 6; }

  fp = &foo;
}
is exactly equivalent to:
int function(char c) fp;

void test() {
  fp = function int(char c) { return 6;} ;
}
And:
int abc(int delegate(long i));

void test() {
  int b = 3;
  int foo(long c) { return 6 + b; }

  abc(&foo);
}
is exactly equivalent to:
int abc(int delegate(long i));

void test() {
  int b = 3;

  abc( delegate int(long c) { return 6 + b; } );
}

and the following where the return type int is inferred:

int abc(int delegate(long i));

void test() {
  int b = 3;

  abc( (long c) { return 6 + b; } );
}
Anonymous delegates can behave like arbitrary statement literals. For example, here an arbitrary statement is executed by a loop:
double test() {
  double d = 7.6;
  float f = 2.3;

  void loop(int k, int j, void delegate() statement) {
    for (int i = k; i < j; i++) {
      statement();
    }
  }

  loop(5, 100, { d += 1; } );
  loop(3, 10,  { f += 3; } );

  return d + f;
}
When comparing with nested functions, the function form is analogous to static or non-nested functions, and the delegate form is analogous to non-static nested functions. In other words, a delegate literal can access stack variables in its enclosing function, a function literal cannot.

Assert Expressions

AssertExpression:
    assert ( AssignExpression )
    assert ( AssignExpression , AssignExpression )

Asserts evaluate the AssignExpression. If it evaluates to a non-null class reference, the class invariant is run. Otherwise, if it evaluates to a non-null pointer to a struct, the struct invariant is run. Otherwise, if the result is false, an AssertError is thrown. If the result is true, then no exception is thrown. It is an error if the expression contains any side effects that the program depends on. The compiler may optionally not evaluate assert expressions at all. The result type of an assert expression is void. Asserts are a fundamental part of the Contract Programming support in D.

The expression assert(0) is a special case; it signifies that it is unreachable code. Either AssertError is thrown at runtime if it is reachable, or the execution is halted (on the x86 processor, a HLT instruction can be used to halt execution). The optimization and code generation phases of compilation may assume that it is unreachable code.

The second AssignExpression, if present, must be implicitly convertible to type char[]. It is evaluated if the result is false, and the string result is appended to the AssertError's message.

void main() {
  assert(0, "an" ~ " error message");
}

When compiled and run, it will produce the message:

Error: AssertError Failure test.d(3) an error message

Mixin Expressions

MixinExpression:
    mixin ( AssignExpression )

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid AssignExpression, and is compiled as such.

int foo(int x) {
  return mixin("x + 1") * 7;  // same as ((x + 1) * 7)
}

Import Expressions

ImportExpression:
    import ( AssignExpression )

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string are interpreted as a file name. The file is read, and the exact contents of the file become a string literal.

Implementations may restrict the file name in order to avoid directory traversal security vulnerabilities. A possible restriction might be to disallow any path components in the file name.

void foo() {
  // Prints contents of file foo.txt
  writefln( import("foo.txt") );
}

Typeid Expressions

TypeidExpression:
    typeid ( Type )

Returns an instance of class TypeInfo corresponding to Type.

IsExpression

IsExpression:
    is ( Type )
    is ( Type : TypeSpecialization )
    is ( Type == TypeSpecialization )
    is ( Type Identifier )
    is ( Type Identifier : TypeSpecialization )
    is ( Type Identifier == TypeSpecialization )

TypeSpecialization:
    Type
  typedef
    struct
    union
    class
    interface
    enum
    function
    delegate
    super
IsExpressions are evaluated at compile time and are used for checking for valid types, comparing types for equivalence, determining if one type can be implicitly converted to another, and deducing the subtypes of a type. The result of an IsExpression is an int of type 0 if the condition is not satisified, 1 if it is.

Type is the type being tested. It must be syntactically correct, but it need not be semantically correct. If it is not semantically correct, the condition is not satisfied.

Identifier is declared to be an alias of the resulting type if the condition is satisfied. The Identifier forms can only be used if the IsExpression appears in a StaticIfCondition.

TypeSpecialization is the type that Type is being compared against.

The forms of the IsExpression are:

  1. is ( Type )
    The condition is satisfied if Type is semantically correct (it must be syntactically correct regardless).
    alias int func(int);    // func is a alias to a function type
void foo() {
  if (is(func[]) ) // not satisfied because arrays of
                        // functions are not allowed
    writefln("satisfied");
  else
    writefln("not satisfied");

  if (is([][]))  // error, [][] is not a syntactically valid type
    ...
}
  2. is ( Type : TypeSpecialization )
    The condition is satisfied if Type is semantically correct and it is the same as or can be implicitly converted to TypeSpecialization. TypeSpecialization is only allowed to be a Type.
    alias short bar;
void foo(bar x) {
  if ( is(bar : int) )   // satisfied because short can be
                              // implicitly converted to int
    writefln("satisfied");
  else
    writefln("not satisfied");
}
  3. is ( Type == TypeSpecialization )
    The condition is satisfied if Type is semantically correct and is the same type as TypeSpecialization.

    If TypeSpecialization is one of typedef struct union class interface enum function delegate then the condition is satisifed if Type is one of those.

    alias short bar;
typedef char foo;
void test(bar x) {
  if ( is(bar == int) ) // not satisfied because short is not
                        // the same type as int
    writefln("satisfied");
  else
    writefln("not satisfied");
 if ( is(foo == typedef) ) // satisfied because foo is a typedef
    writefln("satisfied");
  else
    writefln("not satisfied");
}
  4. is ( Type Identifier )
    The condition is satisfied if Type is semantically correct. If so, Identifier is declared to be an alias of Type.
    alias short bar;
void foo(bar x) {
  static if ( is(bar T) )
    alias T S;
  else
    alias long S;

  writefln(typeid(S));  // prints "short"
  if ( is(bar T) )  // error, Identifier T form can
                      // only be in StaticIfConditions
    ...
}
  5. is ( Type Identifier : TypeSpecialization )

    The condition is satisfied if Type is the same as TypeSpecialization, or if Type is a class and TypeSpecialization is a base class or base interface of it. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type.

    alias int bar;
alias long* abc;
void foo(bar x, abc a) {
  static if ( is(bar T : int) )
    alias T S;
  else
    alias long S;

  writefln(typeid(S));  // prints "int"

  static if ( is(abc U : U*) )
  {
    U u;
    writefln(typeid(typeof(u)));  // prints "long"
  }
}

    The way the type of Identifier is determined is analogous to the way template parameter types are determined by TemplateTypeParameterSpecialization.

  6. is ( Type Identifier == TypeSpecialization )

    The condition is satisfied if Type is semantically correct and is the same as TypeSpecialization. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type.

    If TypeSpecialization is one of typedef struct union class interface enum function delegate then the condition is satisifed if Type is one of those. Furthermore, Identifier is set to be an alias of the type:

    keyword | alias type for Identifier
    typedef | the type that Type is a typedef of
    struct | Type
    union | Type
    class | Type
    interface | Type
    super | TypeTuple of base classes and interfaces
    enum | the base type of the enum
    function | TypeTuple of the function parameter types. For C- and D-style variadic functions, only the non-variadic parameters are included. For typesafe variadic functions, the ... is ignored.
    delegate | the function type of the delegate
    return | the return type of the function, delegate, or function pointer
    alias short bar;
enum E : byte { Emember }
void foo(bar x) {
  static if ( is(bar T == int) ) // not satisfied, short is not int
    alias T S;
  alias T U;       // error, T is not defined

  static if ( is(E V == enum) )  // satisified, E is an enum
    V v;           // v is declared to be a byte
}

    For example, to test to see if X is a typedef and its base type is int:

    typedef int X;

static if (is(X base == typedef)) {
  static assert(is(base == int), "base of typedef X is not int");
}
else {
  static assert(0, "X is not a typedef");
}

Associativity and Commutativity

An implementation may rearrange the evaluation of expressions according to arithmetic associativity and commutativity rules as long as, within that thread of execution, no observable difference is possible.

This rule precludes any associative or commutative reordering of floating point expressions.


Statements

Last update Sun Dec 30 20:34:42 2012

Statements

C and C++ programmers will find the D statements very familiar, with a few interesting additions.
Statement:
    ;
    NonEmptyStatement
    ScopeBlockStatement

NoScopeNonEmptyStatement:
    NonEmptyStatement
    BlockStatement

NoScopeStatement:
    ;
    NonEmptyStatement
    BlockStatement

NonEmptyOrScopeBlockStatement:
    NonEmptyStatement
    ScopeBlockStatement

NonEmptyStatement:
    NonEmptyStatementNoCaseNoDefault
    CaseStatement
    DefaultStatement

NonEmptyStatementNoCaseNoDefault:
    LabeledStatement
    ExpressionStatement
    DeclarationStatement
    IfStatement
    WhileStatement
    DoStatement
    ForStatement
    ForeachStatement
    SwitchStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    GotoStatement
    WithStatement
    SynchronizedStatement
    TryStatement
    ScopeGuardStatement
    ThrowStatement
  VolatileStatement
    AsmStatement
    PragmaStatement
    MixinStatement

    ConditionalStatement
    StaticAssert
    TemplateMixin
    ImportDeclaration

Any ambiguities in the grammar between Statements and Declarations are resolved by the declarations taking precedence. If a Statement is desired instead, wrapping it in parentheses will disambiguate it in favor of being a Statement.

Scope Statements

ScopeStatement:
    NonEmptyStatement
    BlockStatement

A new scope for local symbols is introduced for the NonEmptyStatement or BlockStatement.

Even though a new scope is introduced, local symbol declarations cannot shadow (hide) other local symbol declarations in the same function.

void func1(int x) {
  int x;    // illegal, x shadows parameter x

  int y;

  { int y; } // illegal, y shadows enclosing scope's y

  void delegate() dg;
  dg = { int y; }; // ok, this y is not in the same function

  struct S {
    int y;    // ok, this y is a member, not a local
  }

  { int z; }
  { int z; }  // ok, this z is not shadowing the other z

  { int t; }
  { t++;   }  // illegal, t is undefined
}

The idea is to avoid bugs in complex functions caused by scoped declarations inadvertently hiding previous ones. Local names should all be unique within a function.

Scope Block Statements

ScopeBlockStatement:
    BlockStatement

A scope block statement introduces a new scope for the BlockStatement.

Labeled Statements

Statements can be labeled. A label is an identifier that precedes a statement.

LabeledStatement:
    Identifier : NoScopeStatement

Any statement can be labeled, including empty statements, and so can serve as the target of a goto statement. Labeled statements can also serve as the target of a break or continue statement.

Labels are in a name space independent of declarations, variables, types, etc. Even so, labels cannot have the same name as local declarations. The label name space is the body of the function they appear in. Label name spaces do not nest, i.e. a label inside a block statement is accessible from outside that block.

Block Statement

BlockStatement:
    { }
    { StatementList }

StatementList:
    Statement
    Statement StatementList

A block statement is a sequence of statements enclosed by { }. The statements are executed in lexical order.

Expression Statement

ExpressionStatement:
    Expression ;
The expression is evaluated.

Expressions that have no effect, like (x + x), are illegal in expression statements. If such an expression is needed, casting it to void will make it legal.

int x;
x++;               // ok
x;                 // illegal
1+1;               // illegal
cast(void)(x + x); // ok

Declaration Statement

Declaration statements declare variables and types.
DeclarationStatement:
    Declaration

Some declaration statements:

int a;        // declare a as type int and initialize it to 0
struct S { }  // declare struct s
alias int myint;

If Statement

If statements provide simple conditional execution of statements.
IfStatement:
    if ( IfCondition ) ThenStatement
    if ( IfCondition ) ThenStatement else ElseStatement

IfCondition:
    Expression
    auto Identifier = Expression
    BasicType Declarator = Expression

ThenStatement:
    ScopeStatement

ElseStatement:
    ScopeStatement
Expression is evaluated and must have a type that can be converted to a boolean. If it's true the ThenStatement is transferred to, else the ElseStatement is transferred to.

The 'dangling else' parsing problem is solved by associating the else with the nearest if statement.

If an auto Identifier is provided, it is declared and initialized to the value and type of the Expression. Its scope extends from when it is initialized to the end of the ThenStatement.

If a Declarator is provided, it is declared and initialized to the value of the Expression. Its scope extends from when it is initialized to the end of the ThenStatement.

import std.regexp;
...
if (auto m = std.regexp.search("abcdef", "b(c)d"))
{
  writefln("[%s]", m.pre);      // prints [a]
  writefln("[%s]", m.post);     // prints [ef]
  writefln("[%s]", m.match(0)); // prints [bcd]
  writefln("[%s]", m.match(1)); // prints [c]
  writefln("[%s]", m.match(2)); // prints []
}
else
{
  writefln(m.post);    // error, m undefined
}
writefln(m.pre);         // error, m undefined

While Statement

WhileStatement:
    while ( Expression ) ScopeStatement
While statements implement simple loops. Expression is evaluated and must have a type that can be converted to a boolean. If it's true the ScopeStatement is executed. After the ScopeStatement is executed, the Expression is evaluated again, and if true the ScopeStatement is executed again. This continues until the Expression evaluates to false.
int i = 0;
while (i < 10) {
  foo(i);
  i++;
}
A BreakStatement will exit the loop. A ContinueStatement will transfer directly to evaluating Expression again.

Do Statement

DoStatement:
    do ScopeStatement while ( Expression )
Do while statements implement simple loops. ScopeStatement is executed. Then Expression is evaluated and must have a type that can be converted to a boolean. If it's true the loop is iterated again. This continues until the Expression evaluates to false.
int i = 0;
do {
  foo(i);
} while (++i < 10);
A BreakStatement will exit the loop. A ContinueStatement will transfer directly to evaluating Expression again.

For Statement

For statements implement loops with initialization, test, and increment clauses.
ForStatement:
    for (Initialize Testopt ; Incrementopt) ScopeStatement

Initialize:
    ;
    NoScopeNonEmptyStatement

Test:
    Expression

Increment:
    Expression

Initialize is executed. Test is evaluated and must have a type that can be converted to a boolean. If it's true the statement is executed. After the statement is executed, the Increment is executed. Then Test is evaluated again, and if true the statement is executed again. This continues until the Test evaluates to false.

A BreakStatement will exit the loop. A ContinueStatement will transfer directly to the Increment.

A ForStatement creates a new scope. If Initialize declares a variable, that variable's scope extends through the end of the for statement. For example:

for (int i = 0; i < 10; i++)
  foo(i);
is equivalent to:
{
  int i;
  for (i = 0; i < 10; i++)
    foo(i);
}
Function bodies cannot be empty:
for (int i = 0; i < 10; i++)
  ;       // illegal
Use instead:
for (int i = 0; i < 10; i++)
{
}
The Initialize may be omitted. Test may also be omitted, and if so, it is treated as if it evaluated to true.

Foreach Statement

A foreach statement loops over the contents of an aggregate.
ForeachStatement:
    Foreach (ForeachTypeList ; Aggregate) NoScopeNonEmptyStatement

Foreach:
    foreach
    foreach_reverse

ForeachTypeList:
    ForeachType
    ForeachType , ForeachTypeList

ForeachType:
    refopt BasicType Declarator
    refopt Identifier

Aggregate:
    Expression

Aggregate is evaluated. It must evaluate to an expression of type static array, dynamic array, associative array, struct, class, delegate, or tuple. The NoScopeNonEmptyStatement is executed, once for each element of the aggregate. At the start of each iteration, the variables declared by the ForeachTypeList are set to be a copy of the elements of the aggregate. If the variable is ref, it is a reference to the contents of that aggregate.

The aggregate must be loop invariant, meaning that elements to the aggregate cannot be added or removed from it in the NoScopeNonEmptyStatement.

Foreach over Arrays

If the aggregate is a static or dynamic array, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the array, one by one. The type of the variable must match the type of the array contents, except for the special cases outlined below. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of int, uint or size_t type, it cannot be ref, and it is set to be the index of the array element.

char[] a;
...
foreach (int i, char c; a)
{
  writefln("a[%d] = '%c'", i, c);
}

For foreach, the elements for the array are iterated over starting at index 0 and continuing to the maximum of the array. For foreach_reverse, the array elements are visited in the reverse order.

Foreach over Arrays of Characters

If the aggregate expression is a static or dynamic array of chars, wchars, or dchars, then the Type of the value can be any of char, wchar, or dchar. In this manner any UTF array can be decoded into any UTF type:

char[] a = "\xE2\x89\xA0";  // \u2260 encoded as 3 UTF-8 bytes

foreach (dchar c; a)
{
  writefln("a[] = %x", c); // prints 'a[] = 2260'
}

dchar[] b = "\u2260"d;

foreach (char c; b)
{
  writef("%x, ", c);  // prints 'e2, 89, a0, '
}

Aggregates can be string literals, which can be accessed as char, wchar, or dchar arrays:

void test() {
  foreach (char c; "ab") {
    writefln("'%s'", c);
  }
  foreach (wchar w; "xy") {
    writefln("'%s'", w);
  }
}

which would print:

'a'
'b'
'x'
'y'

Foreach over Associative Arrays

If the aggregate expression is an associative array, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the array, one by one. The type of the variable must match the type of the array contents. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of the same type as the indexing type of the associative array. It cannot be ref, and it is set to be the index of the array element. The order in which the elements of the array is unspecified for foreach. foreach_reverse for associative arrays is illegal.

double[char[]] a; // index type is char[], value type is double
...
foreach (char[] s, double d; a)
{
  writefln("a['%s'] = %g", s, d);
}

Foreach over Structs and Classes with opApply

If it is a struct or class object, the foreach is defined by the special opApply member function. The foreach_reverse behavior is defined by the special opApplyReverse member function. These special functions must be defined by the type in order to use the corresponding foreach statement. The functions have the type:

int opApply(int delegate(ref Type [, ...]) dg);

int opApplyReverse(int delegate(ref Type [, ...]) dg);

where Type matches the Type used in the ForeachType declaration of Identifier. Multiple ForeachTypes correspond with multiple Type's in the delegate type passed to opApply or opApplyReverse. There can be multiple opApply and opApplyReverse functions, one is selected by matching the type of dg to the ForeachTypes of the ForeachStatement. The body of the apply function iterates over the elements it aggregates, passing them each to the dg function. If the dg returns 0, then apply goes on to the next element. If the dg returns a nonzero value, apply must cease iterating and return that value. Otherwise, after done iterating across all the elements, apply will return 0.

For example, consider a class that is a container for two elements:

class Foo {
  uint[2] array;

  int opApply(int delegate(ref uint) dg)
  {
    int result = 0;

    for (int i = 0; i < array.length; i++)
    {
      result = dg(array[i]);
      if (result)
        break;
    }
    return result;
  }
}
An example using this might be:
void test() {
  Foo a = new Foo();

  a.array[0] = 73;
  a.array[1] = 82;

  foreach (uint u; a)
  {
    writefln("%d", u);
  }
}
which would print:
73
82

Foreach over Delegates

If Aggregate is a delegate, the type signature of the delegate is of the same as for opApply. This enables many different named looping strategies to coexist in the same class or struct.

Foreach over Tuples

If the aggregate expression is a tuple, there can be one or two variables declared. If one, then the variable is said to be the value set to the elements of the tuple, one by one. If the type of the variable is given, it must match the type of the tuple contents. If it is not given, the type of the variable is set to the type of the tuple element, which may change from iteration to iteration. If there are two variables declared, the first is said to be the index and the second is said to be the value. The index must be of int or uint type, it cannot be ref, and it is set to be the index of the tuple element.

If the tuple is a list of types, then the foreach statement is executed once for each type, and the value is aliased to that type.

import std.stdio;
import std.typetuple; // for TypeTuple

void main() {
  alias TypeTuple!(int, long, double) TL;

  foreach (T; TL)
  {
    writefln(typeid(T));
  }
}

Prints:

int
long
double

Foreach Ref Parameters

ref can be used to update the original elements:

void test() {
  static uint[2] a = [7, 8];

  foreach (ref uint u; a)
  {
    u++;
  }
  foreach (uint u; a)
  {
    writefln("%d", u);
  }
}
which would print:
8
9

ref can not be applied to the index values.

If not specified, the Types in the ForeachType can be inferred from the type of the Aggregate.

Foreach Restrictions

The aggregate itself must not be resized, reallocated, free'd, reassigned or destructed while the foreach is iterating over the elements.

int[] a;
int[] b;
foreach (int i; a)
{
  a = null;                 // error
  a.length = a.length + 10; // error
  a = b;                    // error
}
a = null;                   // ok

Break and Continue out of Foreach

A BreakStatement in the body of the foreach will exit the foreach, a ContinueStatement will immediately start the next iteration.

Switch Statement

A switch statement goes to one of a collection of case statements depending on the value of the switch expression.
SwitchStatement:
    switch ( Expression ) ScopeStatement

CaseStatement:
    case ArgumentList : ScopeStatementList

DefaultStatement:
    default : ScopeStatementList

ScopeStatementList:
    StatementListNoCaseNoDefault

StatementListNoCaseNoDefault:
    StatementNoCaseNoDefault
    StatementNoCaseNoDefault StatementListNoCaseNoDefault

StatementNoCaseNoDefault:
    ;
    NonEmptyStatementNoCaseNoDefault
    ScopeBlockStatement

Expression is evaluated. The result type T must be of integral type or char[], wchar[] or dchar[]. The result is compared against each of the case expressions. If there is a match, the corresponding case statement is transferred to.

The case expressions, ArgumentList, are a comma separated list of expressions.

If none of the case expressions match, and there is a default statement, the default statement is transferred to.

If none of the case expressions match, and there is not a default statement, a std.switcherr.SwitchError is thrown.

The case expressions must all evaluate to a constant value or array. They must be implicitly convertible to the type of the switch Expression.

Case expressions must all evaluate to distinct values. There may not be two or more default statements.

The ScopeStatementList introduces a new scope.

Case statements and default statements associated with the switch can be nested within block statements; they do not have to be in the outermost block. For example, this is allowed:

switch (i) {
  case 1:
  {
    case 2:
  }
    break;
}

Case statements 'fall through' to subsequent case values. A break statement will exit the switch BlockStatement. For example:

switch (i) {
  case 1:
    x = 3;
  case 2:
    x = 4;
    break;

  case 3,4,5:
    x = 5;
    break;
}

will set x to 4 if i is 1.

Strings can be used in switch expressions. For example:

char[] name;
...
switch (name) {
  case "fred":
  case "sally":
    ...
}

For applications like command line switch processing, this can lead to much more straightforward code, being clearer and less error prone. char, wchar and dchar strings are allowed.

Implementation Note: The compiler's code generator may assume that the case statements are sorted by frequency of use, with the most frequent appearing first and the least frequent last. Although this is irrelevant as far as program correctness is concerned, it is of performance interest.

Continue Statement

ContinueStatement:
    continue Identifieropt ;
A continue aborts the current iteration of its enclosing loop statement, and starts the next iteration. continue executes the next iteration of its innermost enclosing while, for, foreach, or do loop. The increment clause is executed.

If continue is followed by Identifier, the Identifier must be the label of an enclosing while, for, or do loop, and the next iteration of that loop is executed. It is an error if there is no such statement.

Any intervening finally clauses are executed, and any intervening synchronization objects are released.

Note: If a finally clause executes a return, throw, or goto out of the finally clause, the continue target is never reached.

for (i = 0; i < 10; i++)
{
  if (foo(i))
    continue;
  bar();
}

Break Statement

BreakStatement:
    break Identifieropt ;
A break exits the enclosing statement. break exits the innermost enclosing while, for, foreach, do, or switch statement, resuming execution at the statement following it.

If break is followed by Identifier, the Identifier must be the label of an enclosing while, for, do or switch statement, and that statement is exited. It is an error if there is no such statement.

Any intervening finally clauses are executed, and any intervening synchronization objects are released.

Note: If a finally clause executes a return, throw, or goto out of the finally clause, the break target is never reached.

for (i = 0; i < 10; i++)
{
  if (foo(i))
    break;
}

Return Statement

ReturnStatement:
    return Expressionopt ;
A return exits the current function and supplies its return value. Expression is required if the function specifies a return type that is not void. The Expression is implicitly converted to the function return type.

At least one return statement, throw statement, or assert(0) expression is required if the function specifies a return type that is not void, unless the function contains inline assembler code.

Before the function actually returns, any objects with scope storage duration are destroyed, any enclosing finally clauses are executed, any scope(exit) statements are executed, any scope(success) statements are executed, and any enclosing synchronization objects are released.

The function will not return if any enclosing finally clause does a return, goto or throw that exits the finally clause.

If there is an out postcondition (see Contract Programming), that postcondition is executed after the Expression is evaluated and before the function actually returns.

int foo(int x)
{
    return x + 3;
}

Goto Statement

GotoStatement:
    goto Identifier ;
    goto default ;
    goto case ;
    goto case Expression ;
A goto transfers to the statement labeled with Identifier.
  if (foo)
    goto L1;
  x = 3;
L1:
  x++;
The second form, goto default;, transfers to the innermost DefaultStatement of an enclosing SwitchStatement.

The third form, goto case;, transfers to the next CaseStatement of the innermost enclosing SwitchStatement.

The fourth form, goto case Expression;, transfers to the CaseStatement of the innermost enclosing SwitchStatement with a matching Expression.

switch (x)
{
  case 3:
    goto case;
  case 4:
    goto default;
  case 5:
    goto case 4;
  default:
    x = 4;
    break;
}
Any intervening finally clauses are executed, along with releasing any intervening synchronization mutexes.

It is illegal for a GotoStatement to be used to skip initializations.

With Statement

The with statement is a way to simplify repeated references to the same object.
WithStatement:
    with ( Expression ) ScopeStatement
    with ( Symbol ) ScopeStatement
    with ( TemplateInstance ) ScopeStatement
where Expression evaluates to a class reference or struct instance. Within the with body the referenced object is searched first for identifier symbols. The WithStatement
with (expression)
{
  ...
  ident;
}
is semantically equivalent to:
{
  Object tmp;
  tmp = expression;
  ...
  tmp.ident;
}

Note that Expression only gets evaluated once. The with statement does not change what this or super refer to.

For Symbol which is a scope or TemplateInstance, the corresponding scope is searched when looking up symbols. For example:

struct Foo {
  alias int Y;
}
...
Y y;        // error, Y undefined
with (Foo) {
  Y y;      // same as Foo.Y y;
}

Synchronized Statement

The synchronized statement wraps a statement with a mutex to synchronize access among multiple threads.

SynchronizedStatement:
    synchronized ScopeStatement
    synchronized ( Expression ) ScopeStatement

Synchronized allows only one thread at a time to execute ScopeStatement by using a mutex.

What mutex is used is determined by the Expression. If there is no Expression, then a global mutex is created, one per such synchronized statement. Different synchronized statements will have different global mutexes.

If there is an Expression, it must evaluate to either an Object or an instance of an Interface, in which case it is cast to the Object instance that implemented that Interface. The mutex used is specific to that Object instance, and is shared by all synchronized statements referring to that instance.

The synchronization gets released even if ScopeStatement terminates with an exception, goto, or return.

Example:

synchronized { ... }

This implements a standard critical section.

Try Statement

Exception handling is done with the try-catch-finally statement.
TryStatement:
    try ScopeStatement Catches
    try ScopeStatement Catches FinallyStatement
    try ScopeStatement FinallyStatement

Catches:
    LastCatch
    Catch
    Catch Catches

LastCatch:
    catch NoScopeNonEmptyStatement

Catch:
    catch ( CatchParameter ) NoScopeNonEmptyStatement

CatchParameter:
    BasicType Identifier

FinallyStatement:
    finally NoScopeNonEmptyStatement

CatchParameter declares a variable v of type T, where T is Object or derived from Object. v is initialized by the throw expression if T is of the same type or a base class of the throw expression. The catch clause will be executed if the exception object is of type T or derived from T.

If just type T is given and no variable v, then the catch clause is still executed.

It is an error if any CatchParameter type T1 hides a subsequent Catch with type T2, i.e. it is an error if T1 is the same type as or a base class of T2.

LastCatch catches all exceptions.

The FinallyStatement is always executed, whether the try ScopeStatement exits with a goto, break, continue, return, exception, or fall-through.

If an exception is raised in the FinallyStatement and is not caught before the FinallyStatement is executed, the new exception replaces any existing exception:

import std.stdio;

int main() {
  try {
    try {
      throw new Exception("first");
    }
    finally {
      writefln("finally");
      throw new Exception("second");
    }
  }
  catch(Exception e) {
    writefln("catch %s", e.msg);
  }
  writefln("done");
  return 0;
}
prints:
finally
catch second
done

A FinallyStatement may not exit with a goto, break, continue, or return; nor may it be entered with a goto.

A FinallyStatement may not contain any Catches. This restriction may be relaxed in future versions.

Throw Statement

Throw an exception.
ThrowStatement:
    throw Expression ;
Expression is evaluated and must be an Object reference. The Object reference is thrown as an exception.
throw new Exception("message");

Scope Guard Statement

ScopeGuardStatement:
    scope(exit) NonEmptyOrScopeBlockStatement
    scope(success) NonEmptyOrScopeBlockStatement
    scope(failure) NonEmptyOrScopeBlockStatement
The ScopeGuardStatement executes NonEmptyOrScopeBlockStatement at the close of the current scope, rather than at the point where the ScopeGuardStatement appears. scope(exit) executes NonEmptyOrScopeBlockStatement when the scope exits normally or when it exits due to exception unwinding. scope(failure) executes NonEmptyOrScopeBlockStatement when the scope exits due to exception unwinding. scope(success) executes NonEmptyOrScopeBlockStatement when the scope exits normally.

If there are multiple ScopeGuardStatements in a scope, they are executed in the reverse lexical order in which they appear. If any scope instances are to be destructed upon the close of the scope, they also are interleaved with the ScopeGuardStatements in the reverse lexical order in which they appear.

writef("1"); {
  writef("2");
  scope(exit) writef("3");
  scope(exit) writef("4");
  writef("5");
}
writefln();
writes:
12543

{
  scope(exit) writef("1");
  scope(success) writef("2");
  scope(exit) writef("3");
  scope(success) writef("4");
}
writefln();
writes:
4321

class Foo {
  this() { writef("0"); }
  ~this() { writef("1"); }
}

try {
  scope(exit) writef("2");
  scope(success) writef("3");
  scope Foo f = new Foo();
  scope(failure) writef("4");
  throw new Exception("msg");
  scope(exit) writef("5");
  scope(success) writef("6");
  scope(failure) writef("7");
}
catch (Exception e) {
}
writefln();
writes:
0412
A scope(exit) or scope(success) statement may not exit with a throw, goto, break, continue, or return; nor may it be entered with a goto.

Volatile Statement

No code motion occurs across volatile statement boundaries.
VolatileStatement:
    volatile Statement
    volatile ;
Statement is evaluated. Memory writes occurring before the Statement are performed before any reads within or after the Statement. Memory reads occurring after the Statement occur after any writes before or within Statement are completed.

A volatile statement does not guarantee atomicity. For that, use synchronized statements.

Asm Statement

Inline assembler is supported with the asm statement:
AsmStatement:
    asm { }
    asm { AsmInstructionList }

AsmInstructionList:
    AsmInstruction ;
    AsmInstruction ; AsmInstructionList
An asm statement enables the direct use of assembly language instructions. This makes it easy to obtain direct access to special CPU features without resorting to an external assembler. The D compiler will take care of the function calling conventions, stack setup, etc.

The format of the instructions is, of course, highly dependent on the native instruction set of the target CPU, and so is implementation defined. But, the format will follow the following conventions:

  • It must use the same tokens as the D language uses.
  • The comment form must match the D language comments.
  • Asm instructions are terminated by a ;, not by an end of line.
These rules exist to ensure that D source code can be tokenized independently of syntactic or semantic analysis.

For example, for the Intel Pentium:

int x = 3;
asm {
  mov EAX,x; // load x and put it in register EAX
}
Inline assembler can be used to access hardware directly:
int gethardware() {
  asm {
    mov EAX, dword ptr 0x1234;
  }
}
For some D implementations, such as a translator from D to C, an inline assembler makes no sense, and need not be implemented. The version statement can be used to account for this:
version (D_InlineAsm_X86)
{
  asm {
    ...
  }
}
else
{
  /* ... some workaround ... */
}

Semantically consecutive AsmStatements shall not have any other instructions (such as register save or restores) inserted between them by the compiler.

Pragma Statement

PragmaStatement:
    Pragma NoScopeStatement

Mixin Statement

MixinStatement:
    mixin ( AssignExpression ) ;

The AssignExpression must evaluate at compile time to a constant string. The text contents of the string must be compilable as a valid StatementList, and is compiled as such.

import std.stdio;

void main() {
  int j;
  mixin("
    int x = 3;
    for (int i = 0; i < 3; i++)
      writefln(x + i, ++j);
    ");    // ok

  const char[] s = "int y;";
  mixin(s);  // ok
  y = 4;     // ok, mixin declared y

  char[] t = "y = 3;";
  mixin(t);  // error, t is not evaluatable at compile time

  mixin("y =") 4; // error, string must be complete statement

  mixin("y =" ~ "4;");  // ok
}


Arrays

Last update Sun Dec 30 20:34:42 2012

Arrays

There are four kinds of arrays:

Kinds of Arrays
Syntax | Description
type* | Pointers to data
type[integer] | Static arrays
type[] | Dynamic arrays
type[type] | Associative arrays

Pointers

int* p;

These are simple pointers to data, analogous to C pointers. Pointers are provided for interfacing with C and for specialized systems work. There is no length associated with it, and so there is no way for the compiler or runtime to do bounds checking, etc., on it. Most conventional uses for pointers can be replaced with dynamic arrays, out and ref parameters, and reference types.

Static Arrays

int[3] s;

These are analogous to C arrays. Static arrays are distinguished by having a length fixed at compile time.

The total size of a static array cannot exceed 16Mb. A dynamic array should be used instead for such large arrays.

A static array with a dimension of 0 is allowed, but no space is allocated for it. It's useful as the last member of a variable length struct, or as the degenerate case of a template expansion.

Static arrays are value types, but as in C static arrays are passed to functions by reference and cannot be returned from functions.

Dynamic Arrays

int[] a;

Dynamic arrays consist of a length and a pointer to the array data. Multiple dynamic arrays can share all or parts of the array data.

Array Declarations

There are two ways to declare arrays, prefix and postfix. The prefix form is the preferred method, especially for non-trivial types.

Prefix Array Declarations

Prefix declarations appear before the identifier being declared and read right to left, so:

int[] a;      // dynamic array of ints
int[4][3] b;  // array of 3 arrays of 4 ints each
int[][5] c;   // array of 5 dynamic arrays of ints.
int*[]*[3] d; // array of 3 pointers to dynamic arrays of pointers to ints
int[]* e;     // pointer to dynamic array of ints

Postfix Array Declarations

Postfix declarations appear after the identifier being declared and read left to right. Each group lists equivalent declarations:

// dynamic array of ints
int[] a;
int a[];

// array of 3 arrays of 4 ints each
int[4][3] b;
int[4] b[3];
int b[3][4];

// array of 5 dynamic arrays of ints.
int[][5] c;
int[] c[5];
int c[5][];

// array of 3 pointers to dynamic arrays of pointers to ints
int*[]*[3] d;
int*[]* d[3];
int* (*d[3])[];

// pointer to dynamic array of ints
int[]* e;
int (*e)[];

Rationale: The postfix form matches the way arrays are declared in C and C++, and supporting this form provides an easy migration path for programmers used to it.

Usage

There are two broad kinds of operations to do on an array - affecting the handle to the array, and affecting the contents of the array. C only has operators to affect the handle. In D, both are accessible.

The handle to an array is specified by naming the array, as in p, s or a:

int* p;
int[3] s;
int[] a;

int* q;
int[3] t;
int[] b;

p = q;     // p points to the same thing q does.
p = s.ptr; // p points to the first element of the array s.
p = a.ptr; // p points to the first element of the array a.

s = ...;   // error, since s is a compiled in static
           // reference to an array.

a = p;     // error, since the length of the array pointed
           // to by p is unknown
a = s;     // a is initialized to point to the s array
a = b;     // a points to the same array as b does

Slicing

Slicing an array means to specify a subarray of it. An array slice does not copy the data, it is only another reference to it. For example:

int[10] a;   // declare array of 10 ints
int[] b;

b = a[1..3]; // a[1..3] is a 2 element array consisting of
             // a[1] and a[2]
foo(b[1]);   // equivalent to foo(0)
a[2] = 3;
foo(b[1]);   // equivalent to foo(3)

The [] is shorthand for a slice of the entire array. For example, the assignments to b:

int[10] a;
int[] b;

b = a;
b = a[];
b = a[0 .. a.length];

are all semantically equivalent.

Slicing is not only handy for referring to parts of other arrays, but for converting pointers into bounds-checked arrays:

int* p;
int[] b = p[0..8];

Array Copying

When the slice operator appears as the lvalue of an assignment expression, it means that the contents of the array are the target of the assignment rather than a reference to the array. Array copying happens when the lvalue is a slice, and the rvalue is an array of or pointer to the same type.

int[3] s;
int[3] t;

s[] = t;           // the 3 elements of t[3] are copied into s[3]
s[] = t[];         // the 3 elements of t[3] are copied into s[3]
s[1..2] = t[0..1]; // same as s[1] = t[0]
s[0..2] = t[1..3]; // same as s[0] = t[1], s[1] = t[2]
s[0..4] = t[0..4]; // error, only 3 elements in s
s[0..2] = t;       // error, different lengths for lvalue and rvalue

Overlapping copies are an error:

s[0..2] = s[1..3]; // error, overlapping copy
s[1..3] = s[0..2]; // error, overlapping copy

Disallowing overlapping makes it possible for more aggressive parallel code optimizations than possible with the serial semantics of C.

Array Setting

If a slice operator appears as the lvalue of an assignment expression, and the type of the rvalue is the same as the element type of the lvalue, then the lvalue's array contents are set to the rvalue.

int[3] s;
int* p;

s[] = 3;     // same as s[0] = 3, s[1] = 3, s[2] = 3
p[0..2] = 3; // same as p[0] = 3, p[1] = 3

Array Concatenation

The binary operator ~ is the cat operator. It is used to concatenate arrays:

int[] a;
int[] b;
int[] c;

a = b ~ c; // Create an array from the concatenation
           // of the b and c arrays

Many languages overload the + operator to mean concatenation. This confusingly leads to, does:

"10" + 3 + 4

produce the number 17, the string "1034" or the string "107" as the result? It isn't obvious, and the language designers wind up carefully writing rules to disambiguate it - rules that get incorrectly implemented, overlooked, forgotten, and ignored. It's much better to have + mean addition, and a separate operator to be array concatenation.

Similarly, the ~= operator means append, as in:

a ~= b; // a becomes the concatenation of a and b

Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array, so:

a = b;           // a refers to b
a = b ~ c[0..0]; // a refers to a copy of b

Appending does not always create a copy, see setting dynamic array length for details.

Array Operations

Many array operations, also known as vector operations, can be expressed at a high level rather than as a loop. For example, the loop:

T[] a, b;
...
for (size_t i = 0; i < a.length; i++)
  a[i] = b[i] + 4;

assigns to the elements of a the elements of b with 4 added to each. This can also be expressed in vector notation as:

T[] a, b;
...
a[] = b[] + 4;

A vector operation is indicated by the slice operator appearing as the lvalue of an =, +=, -=, *=, /=, %=, ^=, &= or |= operator. The rvalue can be an expression consisting either of an array slice of the same length and type as the lvalue or an expression of the element type of the lvalue, in any combination. The operators supported for vector operations are the binary operators +, -, *, /, %, ^, & and |, and the unary operators - and ~.

The lvalue slice and any rvalue slices must not overlap. The vector assignment operators are evaluated right to left, and the other binary operators are evaluated left to right. All operands are evaluated exactly once, even if the array slice has zero elements in it.

The order in which the array elements are computed is implementation defined, and may even occur in parallel. An application must not depend on this order.

Implementation note: many of the more common vector operations are expected to take advantage of any vector math instructions available on the target computer.

Pointer Arithmetic

int[3] abc;              // static array of 3 ints
int[] def = [ 1, 2, 3 ]; // dynamic array of 3 ints

void dibb(int* array) {
  array[2];     // means same thing as *(array + 2)
  *(array + 2); // get 3rd element
}

void diss(int[] array) {
  array[2];     // ok
  *(array + 2); // error, array is not a pointer
}

void ditt(int[3] array) {
  array[2];     // ok
  *(array + 2); // error, array is not a pointer
}

Rectangular Arrays

Experienced FORTRAN numerics programmers know that multidimensional "rectangular" arrays for things like matrix operations are much faster than trying to access them via pointers to pointers resulting from "array of pointers to array" semantics. For example, the D syntax:

double[][] matrix;

declares matrix as an array of pointers to arrays. (Dynamic arrays are implemented as pointers to the array data.) Since the arrays can have varying sizes (being dynamically sized), this is sometimes called "jagged" arrays. Even worse for optimizing the code, the array rows can sometimes point to each other! Fortunately, D static arrays, while using the same syntax, are implemented as a fixed rectangular layout:

double[3][3] matrix;

declares a rectangular matrix with 3 rows and 3 columns, all contiguously in memory. In other languages, this would be called a multidimensional array and be declared as:

double matrix[3,3];

Array Length

Within the [ ] of a static or a dynamic array, the variable length is implicitly declared and set to the length of the array. The symbol $ can also be so used.

int[4] foo;
int[]  bar = foo;
int*   p = &foo[0];

// These expressions are equivalent:
bar[]
bar[0 .. 4]
bar[0 .. length]
bar[0 .. $]
bar[0 .. bar.length]

p[0 .. length]         // 'length' is not defined, since p is not an array
bar[0]+length       // 'length' is not defined, out of scope of [ ]

bar[length-1]  // retrieves last element of the array

Array Properties

Static array properties are:

Static Array Properties
Property | Description
.init | returns the default initializer for the element type.
.sizeof | Returns the array length multiplied by the number of bytes per array element.
.length | Returns the number of elements in the array. This is a fixed quantity for static arrays. It is of type size_t.
.ptr | Returns a pointer to the first element of the array.
.dup | Create a dynamic array of the same size and copy the contents of the array into it.
.idup | Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. D 2.0 only
.reverse | Reverses in place the order of the elements in the array. Returns the array.
.sort | Sorts in place the order of the elements in the array. Returns the array.

Dynamic array properties are:

Dynamic Array Properties
Property | Description
.init | Returns null.
.sizeof | Returns the size of the dynamic array reference, which is 8 in 32-bit builds and 16 on 64-bit builds.
.length | Get/set number of elements in the array. It is of type size_t.
.ptr | Returns a pointer to the first element of the array.
.dup | Create a dynamic array of the same size and copy the contents of the array into it.
.idup | Create a dynamic array of the same size and copy the contents of the array into it. The copy is typed as being immutable. D 2.0 only
.reverse | Reverses in place the order of the elements in the array. Returns the array.
.sort | Sorts in place the order of the elements in the array. Returns the array.

For the .sort property to work on arrays of class objects, the class definition must define the function: int opCmp(Object). This is used to determine the ordering of the class objects. Note that the parameter is of type Object, not the type of the class.

For the .sort property to work on arrays of structs or unions, the struct or union definition must define the function: int opCmp(S) or int opCmp(S*). The type S is the type of the struct or union. This function will determine the sort ordering.

Examples:

int* p;
int[3] s;
int[] a;

p.length; // error, length not known for pointer
s.length; // compile time constant 3
a.length; // runtime value

p.dup;    // error, length not known
s.dup;    // creates an array of 3 elements, copies
          // elements s into it
a.dup;    // creates an array of a.length elements, copies
          // elements of a into it

Setting Dynamic Array Length

The .length property of a dynamic array can be set as the lvalue of an = operator:

array.length = 7;

This causes the array to be reallocated in place, and the existing contents copied over to the new array. If the new array length is shorter, the array is not reallocated, and no data is copied. It is equivalent to slicing the array:

array = array[0..7];
If the new array length is longer, the remainder is filled out with the default initializer.

To maximize efficiency, the runtime always tries to resize the array in place to avoid extra copying. It will always do a copy if the new size is larger and the array was not allocated via the new operator or a previous resize operation.

This means that if there is an array slice immediately following the array being resized, the resized array could overlap the slice; i.e.:

char[] a = new char[20];
char[] b = a[0..10];
char[] c = a[10..20];

b.length = 15; // always resized in place because it is sliced
               // from a[] which has enough memory for 15 chars
b[11] = 'x';   // a[11] and c[1] are also affected

a.length = 1;
a.length = 20; // no net change to memory layout

c.length = 12; // always does a copy because c[] is not at the
               // start of a gc allocation block
c[5] = 'y';    // does not affect contents of a[] or b[]

a.length = 25; // may or may not do a copy
a[3] = 'z';    // may or may not affect b[3] which still overlaps
               // the old a[3]

To guarantee copying behavior, use the .dup property to ensure a unique array that can be resized.

These issues also apply to appending arrays with the ~= operator. Concatenation using the ~ operator is not affected since it always reallocates.

Resizing a dynamic array is a relatively expensive operation. So, while the following method of filling an array:

int[] array;
while (1) {
  c = getinput();
  if (!c)
    break;
  array.length = array.length + 1;
  array[array.length - 1] = c;
}

will work, it will be inefficient. A more practical approach would be to minimize the number of resizes:

int[] array;
array.length = 100;        // guess
for (i = 0; ; i++) {
  c = getinput();
  if (!c)
    break;
  if (i == array.length)
    array.length = array.length * 2;
  array[i] = c;
}
array.length = i;

Picking a good initial guess is an art, but you usually can pick a value covering 99% of the cases. For example, when gathering user input from the console - it's unlikely to be longer than 80.

Functions as Array Properties

If the first parameter to a function is an array, the function can be called as if it were a property of the array:

int[] array;
void foo(int[] a, int x);

foo(array, 3);
array.foo(3);   // means the same thing

Array Bounds Checking

It is an error to index an array with an index that is less than 0 or greater than or equal to the array length. If an index is out of bounds, an ArrayBoundsError exception is raised if detected at runtime, and an error if detected at compile time. A program may not rely on array bounds checking happening, for example, the following program is incorrect:

try {
  for (i = 0; ; i++) {
    array[i] = 5;
  }
}
catch (RangeError) {
  // terminate loop
}
The loop is correctly written:
for (i = 0; i < array.length; i++) {
  array[i] = 5;
}

Implementation Note: Compilers should attempt to detect array bounds errors at compile time, for example:

int[3] foo;
int x = foo[3]; // error, out of bounds

Insertion of array bounds checking code at runtime should be turned on and off with a compile time switch.

Array Initialization

Default Initialization

  • Pointers are initialized to null.
  • Static array contents are initialized to the default initializer for the array element type.
  • Dynamic arrays are initialized to having 0 elements.
  • Associative arrays are initialized to having 0 elements.

Void Initialization

Void initialization happens when the Initializer for an array is void. What it means is that no initialization is done, i.e. the contents of the array will be undefined. This is most useful as an efficiency optimization. Void initializations are an advanced technique and should only be used when profiling indicates that it matters.

Static Initialization of Statically Allocated Arrays

Static initalizations are supplied by a list of array element values enclosed in [ ]. The values can be optionally preceded by an index and a :. If an index is not supplied, it is set to the previous index plus 1, or 0 if it is the first value.

int[3] a = [ 1:2, 3 ]; // a[0] = 0, a[1] = 2, a[2] = 3

This is most handy when the array indices are given by enums:

enum Color { red, blue, green };

int value[Color.max + 1] =
  [ Color.blue :6,
    Color.green:2,
    Color.red  :5 ];

These arrays are statically allocated when they appear in global scope. Otherwise, they need to be marked with const or static storage classes to make them statically allocated arrays.

Special Array Types

Strings

A string is an array of characters. String literals are just an easy way to write character arrays. String literals are immutable (read only).

char[] str;
char[] str1 = "abc";
str[0] = 'b';  // error, "abc" is read only, may crash

The name string is aliased to char[], so the above declarations could be equivalently written as:

string str;
string str1 = "abc";

char[] strings are in UTF-8 format. wchar[] strings are in UTF-16 format. dchar[] strings are in UTF-32 format.

Strings can be copied, compared, concatenated, and appended:

str1 = str2;
if (str1 < str3) ...
func(str3 ~ str4);
str4 ~= str1;

with the obvious semantics. Any generated temporaries get cleaned up by the garbage collector (or by using alloca()). Not only that, this works with any array not just a special String array.

A pointer to a char can be generated:

char* p = &str[3]; // pointer to 4th element
char* p = str;     // pointer to 1st element

Since strings, however, are not 0 terminated in D, when transferring a pointer to a string to C, add a terminating 0:

str ~= "\0";

or use the function std.string.toStringz.

The type of a string is determined by the semantic phase of compilation. The type is one of: char[], wchar[], dchar[], and is determined by implicit conversion rules. If there are two equally applicable implicit conversions, the result is an error. To disambiguate these cases, a cast or a postfix of c, w or d can be used:

cast(wchar [])"abc" // this is an array of wchar characters
"abc"w              // so is this

String literals that do not have a postfix character and that have not been cast can be implicitly converted between string, wstring, and dstring as necessary.

char c;
wchar w;
dchar d;

c = 'b';     // c is assigned the character 'b'
w = 'b';     // w is assigned the wchar character 'b'
w = 'bc';    // error - only one wchar character at a time
w = "b"[0];  // w is assigned the wchar character 'b'
w = "\r"[0]; // w is assigned the carriage return wchar character
d = 'd';     // d is assigned the character 'd'

C's printf() and Strings

printf() is a C function and is not part of D. printf() will print C strings, which are 0 terminated. There are two ways to use printf() with D strings. The first is to add a terminating 0, and cast the result to a char*:

str ~= "\0";
printf("the string is '%s'\n", cast(char*)str);

or:

import std.string;
printf("the string is '%s'\n", std.string.toStringz(str));

String literals already have a 0 appended to them, so can be used directly:

printf("the string is '%s'\n", cast(char*)"string literal");

So, why does the first string literal to printf not need the cast? The first parameter is prototyped as a const(char)*, and a string literal can be implicitly cast to a const(char)*. The rest of the arguments to printf, however, are variadic (specified by ...), and a string literal is passed as a (length,pointer) combination to variadic parameters.

The second way is to use the precision specifier. The length comes first, followed by the pointer:

printf("the string is '%.*s'\n", str.length, str.ptr);

The best way is to use std.stdio.writefln, which can handle D strings:

import std.stdio;
writefln("the string is '%s'", str);

Implicit Conversions

A pointer T* can be implicitly converted to one of the following:

  • void*

A static array T[dim] can be implicitly converted to one of the following:

  • T[]
  • U[]
  • void[]

A dynamic array T[] can be implicitly converted to one of the following:

  • U[]
  • void[]

Where U is a base class of T.


Associative Arrays

Last update Sun Dec 30 20:34:44 2012

Associative Arrays

Associative arrays have an index that is not necessarily an integer, and can be sparsely populated. The index for an associative array is called the key, and its type is called the KeyType.

Associative arrays are declared by placing the KeyType within the [ ] of an array declaration:

int[string] b;    // associative array b of ints that are
                  // indexed by an array of characters.
                  // The KeyType is string
b["hello"] = 3;   // set value associated with key "hello" to 3
func(b["hello"]); // pass 3 as parameter to func()

Particular keys in an associative array can be removed with the remove function:

b.remove("hello");

The InExpression yields a pointer to the value if the key is in the associative array, or null if not:

int* p;
p = ("hello" in b);
if (p !is (B null))
        ...

KeyTypes cannot be functions or voids.

The element types of an associative array cannot be functions or voids.

Using Classes as the KeyType

Classes can be used as the KeyType. For this to work, the class definition must override the following member functions of class Object:

  • hash_t toHash()
  • int opEquals(Object)
  • int opCmp(Object)

hash_t is an alias to an integral type.

Note that the parameter to opCmp and opEquals is of type Object, not the type of the class in which it is defined.

For example:

class Foo {
  int a, b;

  hash_t toHash() { return a + b; }

  int opEquals(Object o)
  { Foo foo = cast(Foo) o;
    return foo && a == foo.a && b == foo.b;
  }

  int opCmp(Object o)
  { Foo foo = cast(Foo) o;
    if (!foo)
      return -1;
    if (a == foo.a)
      return b - foo.b;
    return a - foo.a;
  }
}

The implementation may use either opEquals or opCmp or both. Care should be taken so that the results of opEquals and opCmp are consistent with each other when the class objects are the same or not.

Using Structs or Unions as the KeyType

If the KeyType is a struct or union type, a default mechanism is used to compute the hash and comparisons of it based on the binary data within the struct value. A custom mechanism can be used by providing the following functions as struct members:

 hash_t toHash();
int opEquals(KeyType* s);
int opCmp(KeyType* s);

For example:

import std.string;

struct MyString {
  string str;

  hash_t toHash()
  { hash_t hash;
    foreach (char c; str)
      hash = (hash * 9) + c;
    return hash;
  }

  bool opEquals(MyString* s)
  {
    return std.string.cmp(this.str, s.str) == 0;
  }

  int opCmp(MyString* s)
  {
    return std.string.cmp(this.str, s.str);
  }
}

The implementation may use either opEquals or opCmp or both. Care should be taken so that the results of opEquals and opCmp are consistent with each other when the struct/union objects are the same or not.

Properties

Properties for associative arrays are:
Associative Array Properties
Property | Description
.sizeof | Returns the size of the reference to the associative array; it is 4 in 32-bit builds and 8 on 64-bit builds.
.length | Returns number of values in the associative array. Unlike for dynamic arrays, it is read-only.
.keys | Returns dynamic array, the elements of which are the keys in the associative array.
.values | Returns dynamic array, the elements of which are the values in the associative array.
.rehash | Reorganizes the associative array in place so that lookups are more efficient. rehash is effective when, for example, the program is done loading up a symbol table and now needs fast lookups in it. Returns a reference to the reorganized array.

Associative Array Example: word count

Let's consider the file is ASCII encoded with LF EOL. In general case we should use dchar c for iteration over code points and functions from std.uni.

import std.file;         // D file I/O
import std.stdio;
import std.ctype;

void main (string[] args) {
  ulong totalWords, totalLines, totalChars;
  ulong[string] dictionary;

  writefln("   lines   words   bytes file");
  foreach (arg; args[1 .. $]) // for each argument except the first one
  {
    ulong wordCount, lineCount, charCount;

    bool inWord;
    size_t wordStart;

    // read file into input buffer
    auto input = cast(string)std.file.read(arg);

    foreach (i, char c; input)
    {
      if (std.ctype.isdigit(c))
      { // c is a digit (0..9)
      }
      else if (std.ctype.isalpha(c))
      { // c is an ASCII letter (A..Z, a..z)
        if (!inWord)
        {
          wordStart = i;
          inWord = true;
          ++wordCount;
        }
      }
      else if (inWord)
      {
        auto word = input[wordStart .. i];
        ++dictionary[word];   // increment count for word
        inWord = false;
      }
      ++charCount;

      // Let's consider the file has LF EOL.
      if (c == '\n')
        ++lineCount;
    }
    if (inWord)
    {
      auto word = input[wordStart .. $];
      ++dictionary[word];
    }

    writefln("%8s%8s%8s %s", lineCount, wordCount, charCount, arg);
    totalWords += wordCount;
    totalLines += lineCount;
    totalChars += charCount;
  }

  if (args.length > 2)
  {
    writefln("-------------------------------------\n%8s%8s%8s total",
            totalLines, totalWords, totalChars);
  }

  writefln("-------------------------------------");
  foreach (word; dictionary.keys.sort)
  {
    writefln("%3s %s", dictionary[word], word);
  }
}


Structs, Unions

Last update Sun Dec 30 20:34:42 2012

Structs & Unions

Whereas classes are reference types, structs are value types. Any C struct can be exactly represented as a D struct. In C++ parlance, a D struct is a POD (Plain Old Data) type, with a trivial constructors and destructors. Structs and unions are meant as simple aggregations of data, or as a way to paint a data structure over hardware or an external type. External types can be defined by the operating system API, or by a file format. Object oriented features are provided with the class data type.

A struct is defined to not have an identity; that is, the implementation is free to make bit copies of the struct as convenient.

Struct, Class Comparison Table
Feature | struct | class | C struct | C++ struct | C++ class
value type | X |  | X | X | X
reference type |  | X |  |  |
data members | X | X | X | X | X
hidden members |  | X |  | X | X
static members | X | X |  | X | X
default member initializers | X | X |  |  |
bit fields |  |  | X | X | X
non-virtual member functions | X | X |  | X | X
virtual member functions |  | X |  | X | X
constructors |  | X |  | X | X
destructors |  | X |  | X | X
RAII |  | X |  | X | X
assign overload |  |  |  | X | X
literals | X |  |  |  |
operator overloading | X | X |  | X | X
inheritance |  | X |  | X | X
invariants | X | X |  |  |
unit tests | X | X |  |  |
synchronizable |  | X |  |  |
parameterizable | X | X |  | X | X
alignment control | X | X |  |  |
member protection | X | X |  | X | X
default public | X | X | X | X |
tag name space |  |  | X | X | X
anonymous | X |  | X | X | X
static constructor | X | X |  |  |
static destructor | X | X |  |  |
AggregateDeclaration:
    struct Identifier StructBody
    union Identifier StructBody
    struct Identifier ;
    union Identifier ;
    StructTemplateDeclaration
    UnionTemplateDeclaration

StructBody:
    { }
    { StructBodyDeclarations }

StructBodyDeclarations:
    StructBodyDeclaration
    StructBodyDeclaration StructBodyDeclarations

StructBodyDeclaration:
    DeclDef
    StructAllocator
    StructDeallocator

StructAllocator:
    ClassAllocator

StructDeallocator:
    ClassDeallocator

They work like they do in C, with the following exceptions:

  • no bit fields
  • alignment can be explicitly specified
  • no separate tag name space - tag names go into the current scope
  • declarations like:
    struct ABC x;
    are not allowed, replace with:
    ABC x;
  • anonymous structs/unions are allowed as members of other structs/unions
  • Default initializers for members can be supplied.
  • Member functions and static members are allowed.

Opaque Structs and Unions

Opaque struct and union declarations do not have a StructBody:

struct S;
union U;

The members are completely hidden to the user, and so the only operations on those types are ones that do not require any knowledge of the contents of those types. For example:

struct S;
S.sizeof; // error, size is not known
S s;      // error, cannot initialize unknown contents
S* p;     // ok, knowledge of members is not necessary

They can be used to implement the PIMPL idiom.

Static Initialization of Structs

Static struct members are by default initialized to whatever the default initializer for the member is, and if none supplied, to the default initializer for the member's type. If a static initializer is supplied, the members are initialized by the member name, colon, expression syntax. The members may be initialized in any order. Initializers for statics must be evaluatable at compile time. Members not specified in the initializer list are default initialized.
struct S { int a; int b; int c; int d = 7;}
static S x = { a:1, b:2};            // c is set to 0, d to 7
static S z = { c:4, b:5, a:2 , d:5}; // z.a = 2, z.b = 5, z.c = 4, z.d = 5
C-style initialization, based on the order of the members in the struct declaration, is also supported:
static S q = { 1, 2 }; // q.a = 1, q.b = 2, q.c = 0, q.d = 7

Struct literals can also be used to initialize statics, but they must be evaluable at compile time.

static S q = S( 1, 2+3 ); // q.a = 1, q.b = 5, q.c = 0, q.d = 7

The static initializer syntax can also be used to initialize non-static variables, provided that the member names are not given. The initializer need not be evaluatable at compile time.

void test(int i) {
  S q = { 1, i }; // q.a = 1, q.b = i, q.c = 0, q.d = 7
}

Static Initialization of Unions

Unions are initialized explicitly.
union U { int a; double b; }
static U u = { b : 5.0 }; // u.b = 5.0
Other members of the union that overlay the initializer, but occupy more storage, have the extra storage initialized to zero.

Dynamic Initialization of Structs

Structs can be dynamically initialized from another value of the same type:

struct S { int a; }
S t;      // default initialized
t.a = 3;
S s = t;  // s.a is set to 3

If opCall is overridden for the struct, and the struct is initialized with a value that is of a different type, then the opCall operator is called:

struct S {
  int a;

  static S opCall(int v)
  { S s;
    s.a = v;
    return s;
  }

  static S opCall(S v)
  { S s;
    s.a = v.a + 1;
    return s;
  }
}

S s = 3; // sets s.a to 3
S t = s; // sets t.a to 3, S.opCall(s) is not called

Struct Literals

Struct literals consist of the name of the struct followed by a parenthesized argument list:

struct S { int x; float y; }

int foo(S s) { return s.x; }

foo( S(1, 2) ); // set field x to 1, field y to 2

Struct literals are syntactically like function calls. If a struct has a member function named opCall, then struct literals for that struct are not possible. It is an error if there are more arguments than fields of the struct. If there are fewer arguments than fields, the remaining fields are initialized with their respective default initializers. If there are anonymous unions in the struct, only the first member of the anonymous union can be initialized with a struct literal, and all subsequent non-overlapping fields are default initialized.

Struct Properties

Struct Properties
.sizeof | Size in bytes of struct
.alignof | Size boundary struct needs to be aligned on
.tupleof | Gets type tuple of fields

Struct Field Properties

Struct Field Properties
.offsetof Offset in bytes of field from beginning of struct


Classes

Last update Sun Dec 30 20:34:42 2012

Classes

The object-oriented features of D all come from classes. The class hierarchy has as its root the class Object. Object defines a minimum level of functionality that each derived class has, and a default implementation for that functionality.

Classes are programmer defined types. Support for classes are what make D an object oriented language, giving it encapsulation, inheritance, and polymorphism. D classes support the single inheritance paradigm, extended by adding support for interfaces. Class objects are instantiated by reference only.

A class can be exported, which means its name and all its non-private members are exposed externally to the DLL or EXE.

A class declaration is defined:

ClassDeclaration:
    class Identifier BaseClassListopt ClassBody
    ClassTemplateDeclaration

BaseClassList:
    : SuperClass
    : SuperClass , Interfaces
    : Interfaces

SuperClass:
    Identifier

Interfaces:
    Interface
    Interface , Interfaces

Interface:
    Identifier

ClassBody:
    { }
    { ClassBodyDeclarations }

ClassBodyDeclarations:
    ClassBodyDeclaration
    ClassBodyDeclaration ClassBodyDeclarations

ClassBodyDeclaration:
    DeclDef
    Invariant
    ClassAllocator
    ClassDeallocator
Classes consist of:
  • a super class
  • interfaces
  • dynamic fields
  • static fields
  • types
  • member functions
    • static member functions
    • Virtual Functions
    • Synchronized Functions
    • Constructors
    • Destructors
    • Static Constructors
    • Static Destructors
    • SharedStaticConstructors
    • SharedStaticDestructors
    • Class Invariants
    • Unit Tests
    • Class Allocators
    • Class Deallocators
A class is defined:
class Foo {
  ... members ...
}
Note that there is no trailing ; after the closing } of the class definition. It is also not possible to declare a variable var like:
class Foo { } var;
Instead:
class Foo { }
Foo var;

Access Control

Access to class members is controlled using ProtectionAttributes. The default protection attribute is public. Access control does not affect visibility.

Fields

Class members are always accessed with the . operator.

Members of a base class can be accessed by prepending the name of the base class followed by a dot:

class A { int a; }
class B : A { int a; }

void foo(B b) {
  b.a = 3;   // accesses field B.a
  b.A.a = 4; // accesses field A.a

The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes.

Field Properties

The .offsetof property gives the offset in bytes of the field from the beginning of the class instantiation. .offsetof can only be applied to expressions which produce the type of the field itself, not the class type:

class Foo {
  int x;
}
...
void test(Foo foo) {
  size_t o;

  o = Foo.x.offsetof; // error, Foo.x needs a 'this' reference
  o = foo.x.offsetof; // ok
}

Class Properties

The .tupleof property returns an ExpressionTuple of all the fields in the class, excluding the hidden fields and the fields in the base class.

class Foo { int x; long y; }
void test(Foo foo) {
  foo.tupleof[0] = 1; // set foo.x to 1
  foo.tupleof[1] = 2; // set foo.y to 2
  foreach (x; foo.tupleof)
    writef(x);        // prints 12
}

The properties .__vptr and .__monitor give access to the class object's vtbl[] and monitor, respectively, but should not be used in user code.

Super Class

All classes inherit from a super class. If one is not specified, it inherits from Object. Object forms the root of the D class inheritance hierarchy.

Member Functions

Non-static member functions have an extra hidden parameter called this through which the class object's other members can be accessed.

Synchronized Functions

Synchronized class member functions have the storage class synchronized. A static member function is synchronized on the classinfo object for the class, which means that one monitor is used for all static synchronized member functions for that class. For non-static synchronized functions, the monitor used is part of the class object. For example:

class Foo {
  synchronized void bar() { ...statements... }
}

is equivalent to (as far as the monitors go):

class Foo {
  void bar() {
    synchronized (this) { ...statements... }
  }
}

Structs do not have synchronized member functions.

Constructors

Constructor:
        this Parameters FunctionBody

Members are always initialized to the default initializer for their type, which is usually 0 for integer types and NAN for floating point types. This eliminates an entire class of obscure problems that come from neglecting to initialize a member in one of the constructors. In the class definition, there can be a static initializer to be used instead of the default:

class Abc {
  int a;      // default initializer for a is 0
  long b = 7; // default initializer for b is 7
  float f;    // default initializer for f is NAN
}
This static initialization is done before any constructors are called.

Constructors are defined with a function name of this and having no return value:

class Foo {
  this(int x)  // declare constructor for Foo
  {   ...
  }
  this()
  {   ...
  }
}
Base class construction is done by calling the base class constructor by the name super:
class A { this(int y) { } }

class B : A {
  int j;
  this() {
    ...
    super(3);  // call base constructor A.this(3)
    ...
  }
}

Constructors can also call other constructors for the same class in order to share common initializations (this is called delegating constructors):

class C {
  int j;
  this() {
    ...
  }
  this(int i) {
    this();
    j = i;
  }
}
If no call to constructors via this or super appear in a constructor, and the base class has a constructor, a call to super() is inserted at the beginning of the constructor.

If there is no constructor for a class, but there is a constructor for the base class, a default constructor of the form:

this() { }

is implicitly generated.

Class object construction is very flexible, but some restrictions apply:

  1. It is illegal for constructors to mutually call each other, although the compiler is not required to detect it. It will result in undefined behavior.
    this() { this(1); }
this(int i) { this(); } // illegal, cyclic constructor calls
  2. If any constructor call appears inside a constructor, any path through the constructor must make exactly one constructor call:
    this()  { a || super(); }       // illegal

this() { (a) ? this(1) : super(); }     // ok

this() {
  for (...) {
    super();  // illegal, inside loop
  }
}
  3. It is illegal to refer to this implicitly or explicitly prior to making a constructor call.
  4. Constructor calls cannot appear after labels (in order to make it easy to check for the previous conditions in the presence of goto's).

Instances of class objects are created with NewExpressions:

A a = new A(3);

The following steps happen:

  1. Storage is allocated for the object. If this fails, rather than return null, an OutOfMemoryError is thrown. Thus, tedious checks for null references are unnecessary.
  2. The raw data is statically initialized using the values provided in the class definition. The pointer to the vtbl[] (the array of pointers to virtual functions) is assigned. This ensures that constructors are passed fully formed objects for which virtual functions can be called. This operation is equivalent to doing a memory copy of a static version of the object onto the newly allocated one, although more advanced compilers may be able to optimize much of this away.
  3. If there is a constructor defined for the class, the constructor matching the argument list is called.
  4. If class invariant checking is turned on, the class invariant is called at the end of the constructor.

Destructors

Destructor:
    ~ this ( ) FunctionBody
The garbage collector calls the destructor function when the object is deleted. The syntax is:
class Foo {
  ~this() // destructor for Foo
  {
  }
}

There can be only one destructor per class, the destructor does not have any parameters, and has no attributes. It is always virtual.

The destructor is expected to release any resources held by the object.

The program can explicitly inform the garbage collector that an object is no longer referred to (with the delete expression), and then the garbage collector calls the destructor immediately, and adds the object's memory to the free storage. The destructor is guaranteed to never be called twice.

The destructor for the super class automatically gets called when the destructor ends. There is no way to call the super destructor explicitly.

The garbage collector is not guaranteed to run the destructor for all unreferenced objects. Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. This means that destructors cannot reference sub objects. This rule does not apply to auto objects or objects deleted with the DeleteExpression, as the destructor is not being run by the garbage collector, meaning all references are valid.

Objects referenced from the data segment never get collected by the gc.

Static Constructors

StaticConstructor:
    static this ( ) FunctionBody

A static constructor is a function that performs initializations before the main() function gets control. Static constructors are used to initialize static class members with values that cannot be computed at compile time.

Static constructors in other languages are built implicitly by using member initializers that can't be computed at compile time. The trouble with this stems from not having good control over exactly when the code is executed, for example:

class Foo {
  static int a = b + 1;
  static int b = a * 2;
}
What values do a and b end up with, what order are the initializations executed in, what are the values of a and b before the initializations are run, is this a compile error, or is this a runtime error? Additional confusion comes from it not being obvious if an initializer is static or dynamic.

D makes this simple. All member initializations must be determinable by the compiler at compile time, hence there is no order-of-evaluation dependency for member initializations, and it is not possible to read a value that has not been initialized. Dynamic initialization is performed by a static constructor, defined with a special syntax static this().

class Foo {
  static int a;         // default initialized to 0
  static int b = 1;
  static int c = b + a; // error, not a constant initializer

  static this()    // static constructor
  {
    a = b + 1;          // a is set to 2
    b = a * 2;          // b is set to 4
  }
}

If main() returns normally (does not throw an exception), the static destructor is added to the list of functions to be called on program termination. Static constructors have empty parameter lists.

Static constructors within a module are executed in the lexical order in which they appear. All the static constructors for modules that are directly or indirectly imported are executed before the static constructors for the importer.

The static in the static constructor declaration is not an attribute, it must appear immediately before the this:

class Foo {
  static this() { ... } // a static constructor
  static private this() { ... } // not a static constructor
  static {
    this() { ... }      // not a static constructor
  }
  static:
    this() { ... }      // not a static constructor
}

Static Destructors

StaticDestructor:
    static ~ this ( ) FunctionBody
A static destructor is defined as a special static function with the syntax static ~this().
class Foo {
  static ~this() // static destructor
  {
  }
}

A static destructor gets called on program termination, but only if the static constructor completed successfully. Static destructors have empty parameter lists. Static destructors get called in the reverse order that the static constructors were called in.

The static in the static destructor declaration is not an attribute, it must appear immediately before the ~this:

class Foo {
  static ~this() { ... }  // a static destructor
  static private ~this() { ... } // not a static destructor
  static
  {
    ~this() { ... }  // not a static destructor
  }
  static:
    ~this() { ... }  // not a static destructor
}

Class Invariants

Invariant:
    invariant ( ) BlockStatement
Class invariants are used to specify characteristics of a class that always must be true (except while executing a member function). For example, a class representing a date might have an invariant that the day must be 1..31 and the hour must be 0..23:
class Date {
  int day;
  int hour;

  invariant() {
    assert(1 <= day && day <= 31);
    assert(0 <= hour && hour < 24);
  }
}

The class invariant is a contract saying that the asserts must hold true. The invariant is checked when a class constructor completes, at the start of the class destructor. For public or exported functions, the order of execution is:

  1. preconditions
  2. invariant
  3. body
  4. invariant
  5. postconditions

The code in the invariant may not call any public non-static members of the class, either directly or indirectly. Doing so will result in a stack overflow, as the invariant will wind up being called in an infinitely recursive manner.

Since the invariant is called at the start of public or exported members, such members should not be called from constructors.

class Foo {
  public void f() { }
  private void g() { }

  invariant() {
    f();  // error, cannot call public member function from invariant
    g();  // ok, g() is not public
  }
}
The invariant can be checked when a class object is the argument to an assert() expression, as:
Date mydate;
...
assert(mydate);         // check that class Date invariant holds
Invariants contain assert expressions, and so when they fail, they throw a AssertErrors. Class invariants are inherited, that is, any class invariant is implicitly anded with the invariants of its base classes.

There can be only one Invariant per class.

When compiling for release, the invariant code is not generated, and the compiled program runs at maximum speed.

Class Allocators

ClassAllocator:
    new Parameters FunctionBody
A class member function of the form:
new(uint size) {
  ...
}
is called a class allocator. The class allocator can have any number of parameters, provided the first one is of type uint. Any number can be defined for a class, the correct one is determined by the usual function overloading rules. When a new expression:
new Foo;
is executed, and Foo is a class that has an allocator, the allocator is called with the first argument set to the size in bytes of the memory to be allocated for the instance. The allocator must allocate the memory and return it as a void*. If the allocator fails, it must not return a null, but must throw an exception. If there is more than one parameter to the allocator, the additional arguments are specified within parentheses after the new in the NewExpression:
class Foo {
  this(char[] a) { ... }

  new(uint size, int x, int y) {
    ...
  }
}

...

new(1,2) Foo(a);        // calls new(Foo.sizeof,1,2)

Derived classes inherit any allocator from their base class, if one is not specified.

The class allocator is not called if the instance is created on the stack.

See also Explicit Class Instance Allocation.

Class Deallocators

ClassDeallocator:
    delete Parameters FunctionBody
A class member function of the form:
delete(void *p) {
  ...
}
is called a class deallocator. The deallocator must have exactly one parameter of type void*. Only one can be specified for a class. When a delete expression:
delete f;

is executed, and f is a reference to a class instance that has a deallocator, the deallocator is called with a pointer to the class instance after the destructor (if any) for the class is called. It is the responsibility of the deallocator to free the memory.

Derived classes inherit any deallocator from their base class, if one is not specified.

The class allocator is not called if the instance is created on the stack.

See also Explicit Class Instance Allocation.

Scope Classes

A scope class is a class with the scope attribute, as in:
scope class Foo { ... }
The scope characteristic is inherited, so if any classes derived from a scope class are also scope.

An scope class reference can only appear as a function local variable. It must be declared as being scope:

scope class Foo { ... }

void func() {
  Foo f;    // error, reference to scope class must be scope
  scope Foo g = new Foo(); // correct
}
When an scope class reference goes out of scope, the destructor (if any) for it is automatically called. This holds true even if the scope was exited via a thrown exception.

Final Classes

Final classes cannot be subclassed:

final class A { }
class B : A { }  // error, class A is final

Nested Classes

A nested class is a class that is declared inside the scope of a function or another class. A nested class has access to the variables and other symbols of the classes and functions it is nested inside:
class Outer {
  int m;

  class Inner {
    int foo() {
      return m;   // Ok to access member of Outer
    }
  }
}

void func() {
  int m;

  class Inner {
    int foo() {
      return m; // Ok to access local variable m of func()
    }
  }
}
If a nested class has the static attribute, then it can not access variables of the enclosing scope that are local to the stack or need a this:
class Outer {
  int m;
  static int n;

  static class Inner {
    int foo() {
      return m;   // Error, Inner is static and m needs a this
      return n;   // Ok, n is static
    }
  }
}

void func() {
  int m;
  static int n;

  static class Inner {
    int foo() {
      return m;   // Error, Inner is static and m is local to the stack
      return n;   // Ok, n is static
    }
  }
}
Non-static nested classes work by containing an extra hidden member (called the context pointer) that is the frame pointer of the enclosing function if it is nested inside a function, or the this of the enclosing class's instance if it is nested inside a class.

When a non-static nested class is instantiated, the context pointer is assigned before the class's constructor is called, therefore the constructor has full access to the enclosing variables. A non-static nested class can only be instantiated when the necessary context pointer information is available:

class Outer {
  class Inner { }

  static class SInner { }
}

void func() {
  class Nested { }

  Outer o = new Outer;        // Ok
  Outer.Inner oi = new Outer.Inner;   // Error, no 'this' for Outer
  Outer.SInner os = new Outer.SInner; // Ok

  Nested n = new Nested;      // Ok
}
While a non-static nested class can access the stack variables of its enclosing function, that access becomes invalid once the enclosing function exits:
class Base {
  int foo() { return 1; }
}

Base func() {
  int m = 3;

  class Nested : Base {
    int foo() { return m; }
  }

  Base b = new Nested;

  assert(b.foo() == 3);       // Ok, func() is still active
  return b;
}

int test() {
  Base b = func();
  return b.foo();             // Error, func().m is undefined
}
If this kind of functionality is needed, the way to make it work is to make copies of the needed variables within the nested class's constructor:
class Base {
  int foo() { return 1; }
}

Base func() {
  int m = 3;

  class Nested : Base {
    int m_;

    this() { m_ = m; }
    int foo() { return m_; }
  }

  Base b = new Nested;

  assert(b.foo() == 3);       // Ok, func() is still active
  return b;
}

int test() {
  Base b = func();
  return b.foo();             // Ok, using cached copy of func().m
}

A this can be supplied to the creation of an inner class instance by prefixing it to the NewExpression:

class Outer {
  int a;

  class Inner {
    int foo() {
      return a;
    }
  }
}

int bar() {
  Outer o = new Outer;
  o.a = 3;
  Outer.Inner oi = o.new Inner;
  return oi.foo();    // returns 3
}

Here o supplies the this to the outer class instance of Outer.

The property .outer used in a nested class gives the this pointer to its enclosing class. If the enclosing context is not a class, the .outer will give the pointer to it as a void* type.

class Outer {
  class Inner {
    Outer foo() {
      return this.outer;
    }
  }

  void bar() {
    Inner i = new Inner;
    assert(this == i.foo());
  }
}

void test() {
  Outer o = new Outer;
  o.bar();
}

Anonymous Nested Classes

An anonymous nested class is both defined and instantiated with a NewAnonClassExpression:

NewAnonClassExpression:
    new AllocatorArgumentsopt class ClassArgumentsopt SuperClassopt Interfacesopt ClassBody

ClassArguments:
    ( ArgumentListopt )

which is equivalent to:

class Identifier : SuperClass Interfaces
        ClassBody

new (ArgumentList) Identifier (ArgumentList);

where Identifier is the name generated for the anonymous nested class.

)


Interfaces

Last update Sun Dec 30 20:34:43 2012

Interfaces

InterfaceDeclaration:
    interface Identifier BaseInterfaceListopt InterfaceBody
    InterfaceTemplateDeclaration

BaseInterfaceList:
    : InterfaceClasses

InterfaceBody:
    { DeclDefsopt }

Interfaces describe a list of functions that a class that inherits from the interface must implement. A class that implements an interface can be converted to a reference to that interface.

Some operating system objects, like COM/OLE/ActiveX for Win32, have specialized interfaces. D interfaces that are compatible with COM/OLE/ActiveX are called COM Interfaces.

Interfaces cannot derive from classes; only from other interfaces. Classes cannot derive from an interface multiple times.

interface D
{
    void foo();
}

class A : D, D	// error, duplicate interface
{
}
An instance of an interface cannot be created.
interface D
{
    void foo();
}

...

D d = new D();		// error, cannot create instance of interface

Interface member functions do not have implementations.

interface D
{
    void bar() { }	// error, implementation not allowed
}

All interface functions must be defined in a class that inherits from that interface:

interface D
{
    void foo();
}

class A : D
{
    void foo() { }	// ok, provides implementation
}

class B : D
{
    int foo() { }	// error, no void foo() implementation
}
Interfaces can be inherited and functions overridden:
interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A
{
    int foo() { return 2; }
}

...

B b = new B();
b.foo();		// returns 2
D d = cast(D) b;	// ok since B inherits A's D implementation
d.foo();		// returns 2;

Interfaces can be reimplemented in derived classes:

interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, D
{
    int foo() { return 2; }
}

...

B b = new B();
b.foo();		// returns 2
D d = cast(D) b;
d.foo();		// returns 2
A a = cast(A) b;
D d2 = cast(D) a;
d2.foo();		// returns 2, even though it is A's D, not B's D

A reimplemented interface must implement all the interface functions, it does not inherit them from a super class:

interface D
{
    int foo();
}

class A : D
{
    int foo() { return 1; }
}

class B : A, D
{
}		// error, no foo() for interface D

COM Interfaces

A variant on interfaces is the COM interface. A COM interface is designed to map directly onto a Windows COM object. Any COM object can be represented by a COM interface, and any D object with a COM interface can be used by external COM clients.

A COM interface is defined as one that derives from the interface std.c.windows.com.IUnknown. A COM interface differs from a regular D interface in that:

  • It derives from the interface std.c.windows.com.IUnknown.
  • It cannot be the argument of a DeleteExpression.
  • References cannot be upcast to the enclosing class object, nor can they be downcast to a derived interface. To accomplish this, an appropriate QueryInterface() would have to be implemented for that interface in standard COM fashion.
  • Classes derived from COM interfaces are COM classes.
  • The default linkage for member functions of COM classes is extern(System).
  • The first member of the vtbl[] is not the pointer to the InterfaceInfo, but the first virtual function pointer.


Enums

Last update Sun Dec 30 20:34:42 2012

Enums

EnumDeclaration:
    enum EnumTag EnumBody
    enum EnumBody
    enum EnumTag : EnumBaseType EnumBody
    enum : EnumBaseType EnumBody

EnumTag:
    Identifier

EnumBaseType:
    Type

EnumBody:
    EmptyEnumBody
    EnumMembersBody

EmptyEnumBody:
    ;

EnumMembersBody:
    { EnumMembers }

EnumMembers:
    EnumMember
    EnumMember ,
    EnumMember , EnumMembers

EnumMember:
    Identifier
    Identifier = AssignExpression

Enum declarations are used to define a group of constants. They come in two forms:

  1. Named enums, which have an EnumTag.
  2. Anonymous enums, which do not have an EnumTag.

Named Enums

Named enums are used to declare related constants and group them by giving them a unique type. The EnumMembers are declared in the scope of the enum EnumTag. The enum EnumTag declares a new type, and all the EnumMembers have that type.

This defines a new type X which has values X.A=0, X.B=1, X.C=2:

enum X { A, B, C }	// named enum

If the EnumBaseType is not explicitly set, it is set to type int.

A named enum member can be implicitly cast to its EnumBaseType, but EnumBaseType types cannot be implicitly cast to an enum type.

The value of an EnumMember is given by its initializer. If there is no initializer, it is given the value of the previous EnumMember + 1. If it is the first EnumMember, it's value is 0.

An EmptyEnumBody signifies an opaque enum - the enum members are unknown.

Enum Default Initializer

The .init property of an enum type is the value of the first member of that enum. This is also the default initializer for the enum type.

enum X { A=3, B, C }
X x;      // x is initialized to 3

Enum Properties

Enum properties only exist for named enums.

.init | First enum member value
.min | Smallest value of enum
.max | Largest value of enum
.sizeof | Size of storage for an enumerated value

For example:

enum X { A=3, B, C }
X.min    // is X.A
X.max    // is X.C
X.sizeof // is same as int.sizeof

Anonymous Enums

If the enum Identifier is not present, then the enum is an anonymous enum, and the EnumMembers are declared in the scope the EnumDeclaration appears in. No new type is created; the EnumMembers have the type of the EnumBaseType.

The EnumBaseType is the underlying type of the enum.

It must be an integral type. If omitted, it defaults to int.

enum { A, B, C }	// anonymous enum

Defines the constants A=0, B=1, C=2, all of type int.

Enums must have at least one member.

The value of an EnumMember is given by its initializer. If there is no initializer, it is given the value of the previous EnumMember + 1. If it is the first EnumMember, it's value is 0.

enum { A, B = 5+7, C, D = 8+C, E }

Sets A=0, B=12, C=13, D=21, and E=22, all of type int.

enum : long { A = 3, B }

Sets A=3, B=4 all of type long.


Functions

Last update Sun Dec 30 20:34:42 2012

Functions

FunctionBody:
    BlockStatement
    BodyStatement
    InStatement BodyStatement
    OutStatement BodyStatement
    InStatement OutStatement BodyStatement
    OutStatement InStatement BodyStatement

InStatement:
    in BlockStatement

OutStatement:
    out BlockStatement
    out ( Identifier ) BlockStatement

BodyStatement:
    body BlockStatement

Function Return Values

Function return values are considered to be rvalues. This means they cannot be passed by reference to other functions.

Functions Without Bodies

Functions without bodies:

int foo();

that are not declared as abstract are expected to have their implementations elsewhere, and that implementation will be provided at the link step. This enables an implementation of a function to be completely hidden from the user of it, and the implementation may be in another language such as C, assembler, etc.

Virtual Functions

Virtual functions are functions that are called indirectly through a function pointer table, called a vtbl[], rather than directly. All non-static non-private non-template member functions are virtual. This may sound inefficient, but since the D compiler knows all of the class hierarchy when generating code, all functions that are not overridden can be optimized to be non-virtual. In fact, since C++ programmers tend to "when in doubt, make it virtual", the D way of "make it virtual unless we can prove it can be made non-virtual" results, on average, in many more direct function calls. It also results in fewer bugs caused by not declaring a function virtual that gets overridden.

Functions with non-D linkage cannot be virtual, and hence cannot be overridden.

Member template functions cannot be virtual, and hence cannot be overridden.

Functions marked as final may not be overridden in a derived class, unless they are also private. For example:

class A {
  int def() { ... }
  final int foo() { ... }
  final private int bar() { ... }
  private int abc() { ... }
}

class B : A {
  int def() { ... }  // ok, overrides A.def
  int foo() { ... }  // error, A.foo is final
  int bar() { ... }  // ok, A.bar is final private, but not virtual
  int abc() { ... }  // ok, A.abc is not virtual, B.abc is virtual
}

void test(A a) {
  a.def();    // calls B.def
  a.foo();    // calls A.foo
  a.bar();    // calls A.bar
  a.abc();    // calls A.abc
}

void func() {
  B b = new B();
  test(b);
}

Covariant return types are supported, which means that the overriding function in a derived class can return a type that is derived from the type returned by the overridden function:

class A { }
class B : A { }

class Foo {
  A test() { return null; }
}

class Bar : Foo {
  B test() { return null; } // overrides and is covariant with Foo.test()
}

Virtual functions all have a hidden parameter called the this reference, which refers to the class object for which the function is called.

Function Inheritance and Overriding

A functions in a derived class with the same name and parameter types as a function in a base class overrides that function:
class A {
  int foo(int x) { ... }
}

class B : A {
  override int foo(int x) { ... }
}

void test() {
  B b = new B();
  bar(b);
}

void bar(A a) {
  a.foo(1);   // calls B.foo(int)
}

However, when doing overload resolution, the functions in the base class are not considered:

class A {
  int foo(int x) { ... }
  int foo(long y) { ... }
}

class B : A {
  override int foo(long x) { ... }
}

void test() {
  B b = new B();
  b.foo(1);  // calls B.foo(long), since A.foo(int) not considered
  A a = b;
  a.foo(1);    // calls A.foo(int)
}

To consider the base class's functions in the overload resolution process, use an AliasDeclaration:

class A {
  int foo(int x) { ... }
  int foo(long y) { ... }
}

class B : A {
  alias A.foo foo;
  override int foo(long x) { ... }
}

void test() {
  B b = new B();
  bar(b);
}

void bar(A a) {
  a.foo(1);      // calls A.foo(int)
  B b = new B();
  b.foo(1);      // calls A.foo(int)
}

A function parameter's default value is not inherited:

class A {
  void foo(int x = 5) { ... }
}

class B : A {
  void foo(int x = 7) { ... }
}

class C : B {
  void foo(int x) { ... }
}

void test() {
  A a = new A();
  a.foo();       // calls A.foo(5)

  B b = new B();
  b.foo();       // calls B.foo(7)

  C c = new C();
  c.foo();       // error, need an argument for C.foo
}

Inline Functions

There is no inline keyword. The compiler makes the decision whether to inline a function or not, analogously to the register keyword no longer being relevant to a compiler's decisions on enregistering variables. (There is no register keyword either.)

Function Overloading

Functions are overloaded based on how well the arguments to a function can match up with the parameters. The function with the best match is selected. The levels of matching are:

  1. no match
  2. match with implicit conversions
  3. exact match

Each argument (including any this pointer) is compared against the function's corresponding parameter, to determine the match level for that argument. The match level for a function is the worst match level of each of its arguments.

If two or more functions have the same match level, it is an ambiguity error.

Functions defined with non-D linkage cannot be overloaded. because the name mangling does not take the parameter types into account.

Function Parameters

Parameters are in, out, inout or lazy. in is the default; the others work like storage classes. For example:

int foo(in int x, out int y, inout int z, int q);

x is in, y is out, z is inout, and q is in.

  • The function declaration makes it clear what the inputs and outputs to the function are.
  • It eliminates the need for IDL as a separate language.
  • It provides more information to the compiler, enabling more error checking and possibly better code generation.
Parameter Storage Classes
Storage Class | Description
none | parameter becomes a mutable copy of its argument
in | equivalent to none
out | parameter is initialized upon function entry with the default value for its type
inout | parameter is passed by reference
lazy | argument is evaluated by the called function and not by the caller
void foo(out int x) {
  // x is set to int.init,
  // which is 0, at start of foo()
}

int a = 3;
foo(a);
// a is now 0

void abc(out int x) {
  x = 2;
}

int y = 3;
abc(y);
// y is now 2

void def(inout int x) {
  x += 1;
}

int z = 3;
def(z);
// z is now 4

For dynamic array and object parameters, which are passed by reference, in/out/ref apply only to the reference and not the contents.

lazy arguments are evaluated not when the function is called, but when the parameter is evaluated within the function. Hence, a lazy argument can be executed 0 or more times. A lazy parameter cannot be an lvalue.

void dotimes(int n, lazy void exp) {
  while (n--)
    exp();
}

void test() {
  int x;
  dotimes(3, writefln(x++));
}

prints to the console:

0
1
2

A lazy parameter of type void can accept an argument of any type.

Function Default Arguments

Function parameter declarations can have default values:

void foo(int x, int y = 3) {
  ...
}
...
foo(4);   // same as foo(4, 3);

Default parameters are evaluated in the context of the function declaration. If the default value for a parameter is given, all following parameters must also have default values.

Variadic Functions

 Functions taking a variable number of arguments are called variadic functions. A variadic function can take one of three forms:
  1. C-style variadic functions
  2. Variadic functions with type info
  3. Typesafe variadic functions

C-style Variadic Functions

A C-style variadic function is declared as taking a parameter of ... after the required function parameters. It has non-D linkage, such as extern (C):
extern (C) int foo(int x, int y, ...);

foo(3, 4);      // ok
foo(3, 4, 6.8); // ok, one variadic argument
foo(2);         // error, y is a required argument
There must be at least one non-variadic parameter declared.
extern (C) int def(...); // error, must have at least one parameter

C-style variadic functions match the C calling convention for variadic functions, and is most useful for calling C library functions like printf.

Access to variadic arguments is done using the standard library module std.c.stdarg.

import std.c.stdarg;

void test() {
  foo(3, 4, 5);   // first variadic argument is 5
}

int foo(int x, int y, ...) {

  va_list ap;
  version (X86_64)
    va_start(ap, __va_argsave);
  else version (X86)
    va_start(ap, y);  // y is the last named parameter

  int z;
  va_arg(ap, z);  // z is set to 5

  va_end(ap);
}

D-style Variadic Functions

Variadic functions with argument and type info are declared as taking a parameter of ... after the required function parameters. It has D linkage, and need not have any non-variadic parameters declared:
int abc(char c, ...);   // one required parameter: c
int def(...);           // ok
To access them, the following import is required:
import std.stdarg;
These variadic functions have a special local variable declared for them, _argptr, which is a std.stdarg.va_list reference to the first of the variadic arguments. To access the arguments, _argptr must be used in conjuction with va_arg:
import std.stdarg;

void test() {
  foo(3, 4, 5);   // first variadic argument is 5
}

int foo(int x, int y, ...) {

  int z;

  z = va_arg!int(_argptr); // z is set to 5
}
An additional hidden argument with the name _arguments and type TypeInfo[] is passed to the function. _arguments gives the number of arguments and the type of each, enabling the creation of typesafe variadic functions.
import std.stdio;
import std.stdarg;

class Foo { int x = 3; }
class Bar { long y = 4; }

void printargs(int x, ...) {
  writefln("%d arguments", _arguments.length);
  for (int i = 0; i < _arguments.length; i++)
  {
    _arguments[i].print();

    if (_arguments[i] == typeid(int))
    {
      int j = va_arg!(int)(_argptr);
      writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(long))
    {
      long j = va_arg!(long)(_argptr);
      writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(double))
    {
      double d = va_arg!(double)(_argptr);
      writefln("\t%g", d);
    }
    else if (_arguments[i] == typeid(Foo))
    {
      Foo f = va_arg!(Foo)(_argptr);
      writefln("\t%s", f);
    }
    else if (_arguments[i] == typeid(Bar))
    {
      Bar b = va_arg!(Bar)(_argptr);
      writefln("\t%s", b);
    }
    else
      assert(0);
  }
}

void main() {
  Foo f = new Foo();
  Bar b = new Bar();

  writefln("%s", f);
  printargs(1, 2, 3L, 4.5, f, b);
}
which prints:
00870FE0
5 arguments
int
        2
long
        3
double
        4.5
Foo
        00870FE0
Bar
        00870FD0

Typesafe Variadic Functions

Typesafe variadic functions are used when the variable argument portion of the arguments are used to construct an array or class object.

For arrays:

int test() {
  return sum(1, 2, 3) + sum(); // returns 6+0
}

int func() {
  int[3] ii = [4, 5, 6];
  return sum(ii);             // returns 15
}

int sum(int[] ar ...) {
  int s;
  foreach (int x; ar)
    s += x;
  return s;
}
For static arrays:
int test() {
  return sum(2, 3);   // error, need 3 values for array
  return sum(1, 2, 3); // returns 6
}

int func() {
  int[3] ii = [4, 5, 6];
  int[] jj = ii;
  return sum(ii); // returns 15
  return sum(jj); // error, type mismatch
}

int sum(int[3] ar ...) {
  int s;
  foreach (int x; ar)
    s += x;
  return s;
}
For class objects:
class Foo {
  int x;
  string s;

  this(int x, string s) {
    this.x = x;
    this.s = s;
  }
}

void test(int x, Foo f ...);

...

Foo g = new Foo(3, "abc");
test(1, g);         // ok, since g is an instance of Foo
test(1, 4, "def");  // ok
test(1, 5);         // error, no matching constructor for Foo
An implementation may construct the object or array instance on the stack. Therefore, it is an error to refer to that instance after the variadic function has returned:
Foo test(Foo f ...) {
  return f;   // error, f instance contents invalid after return
}

int[] test(int[] a ...) {
  return a;       // error, array contents invalid after return
  return a[0..1]; // error, array contents invalid after return
  return a.dup;   // ok, since copy is made
}
For other types, the argument is built with itself, as in:
int test(int i ...) {
  return i;
}

...
test(3);    // returns 3
test(3, 4); // error, too many arguments
int[] x;
test(x);    // error, type mismatch

Lazy Variadic Functions

If the variadic parameter is an array of delegates with no parameters:

void foo(int delegate()[] dgs ...);

Then each of the arguments whose type does not match that of the delegate is converted to a delegate.

int delegate() dg;
foo(1, 3+x, dg, cast(int delegate())null);

is the same as:

foo( { return 1; }, { return 3+x; }, dg, null );

Local Variables

It is an error to use a local variable without first assigning it a value. The implementation may not always be able to detect these cases. Other language compilers sometimes issue a warning for this, but since it is always a bug, it should be an error.

It is an error to declare a local variable that is never referred to. Dead variables, like anachronistic dead code, are just a source of confusion for maintenance programmers.

It is an error to declare a local variable that hides another local variable in the same function:

void func(int x) {
   int x;     // error, hides previous definition of x
   double y;
   ...
   { char y;  // error, hides previous definition of y
     int z;
   }
   { wchar z; // legal, previous z is out of scope
   }
}

While this might look unreasonable, in practice whenever this is done it either is a bug or at least looks like a bug.

It is an error to return the address of or a reference to a local variable.

It is an error to have a local variable and a label with the same name.

Local Static Variables

Local variables in functions can be declared as static in which case they are statically allocated rather than being allocated on the stack. As such, their value persists beyond the exit of the function.

void foo() {
  static int n;
  if (++n == 100)
    writeln("called 100 times");
}

The initializer for a static variable must be evaluatable at compile time, and they are initialized upon the start of the thread

Although static variable name visibility follows the usual scoping rules, the names of them must be unique within a particular function.

void main() {
  { static int x; }
  { static int x; } // error
  { int i; }
  { int i; } // ok
}

Nested Functions

Functions may be nested within other functions:

int bar(int a) {
  int foo(int b) {
    int abc() { return 1; }

    return b + abc();
  }
  return foo(a);
}

void test() {
  int i = bar(3); // i is assigned 4
}

Nested functions can be accessed only if the name is in scope.

void foo()
{
  void A()
  {
    B(); // error, B() is forward referenced
    C(); // error, C undefined
  }
  void B()
  {
    A(); // ok, in scope
    void C()
    {
      void D()
      {
        A();      // ok
        B();      // ok
        C();      // ok
        D();      // ok
      }
    }
  }
  A(); // ok
  B(); // ok
  C(); // error, C undefined
}

and:

int bar(int a) {
  int foo(int b) { return b + 1; }
  int abc(int b) { return foo(b); }   // ok
  return foo(a);
}

void test() {
  int i = bar(3);     // ok
  int j = bar.foo(3); // error, bar.foo not visible
}

Nested functions have access to the variables and other symbols defined by the lexically enclosing function. This access includes both the ability to read and write them.

int bar(int a) {
  int c = 3;

  int foo(int b) {
    b += c;       // 4 is added to b
    c++;          // bar.c is now 5
    return b + c; // 12 is returned
  }
  c = 4;
  int i = foo(a); // i is set to 12
  return i + c;   // returns 17
}

void test() {
  int i = bar(3); // i is assigned 17
}

This access can span multiple nesting levels:

int bar(int a) {
  int c = 3;

  int foo(int b) {
      int abc() {
          return c;   // access bar.c
      }
      return b + c + abc();
  }
  return foo(3);
}

Static nested functions cannot access any stack variables of any lexically enclosing function, but can access static variables. This is analogous to how static member functions behave.

int bar(int a) {
  int c;
  static int d;

  static int foo(int b) {
    b = d;          // ok
    b = c;          // error, foo() cannot access frame of bar()
    return b + 1;
  }
  return foo(a);
}

Functions can be nested within member functions:

struct Foo {
  int a;

  int bar() {
    int c;

    int foo() {
      return c + a;
    }
    return 0;
  }
}

Member functions of nested classes and structs do not have access to the stack variables of the enclosing function, but do have access to the other symbols:

void test() {
  int j;
  static int s;

  struct Foo {
    int a;

    int bar() {
      int c = s;  // ok, s is static
      int d = j;  // error, no access to frame of test()

      int foo() {
        int e = s;    // ok, s is static
        int f = j;    // error, no access to frame of test()
        return c + a; // ok, frame of bar() is accessible,
                      // so are members of Foo accessible via
                      // the 'this' pointer to Foo.bar()
      }

      return 0;
    }
  }
}

Nested functions always have the D function linkage type.

Unlike module level declarations, declarations within function scope are processed in order. This means that two nested functions cannot mutually call each other:

void test() {
  void foo() { bar(); } // error, bar not defined
  void bar() { foo(); } // ok
}

One solution is declare both functions as members of a nested struct. Another solution is to use a delegate:

void test() {
  void delegate() fp;
  void foo() { fp(); }
  void bar() { foo(); }
  fp = &bar;
}

Nested functions cannot be overloaded.

Delegates, Function Pointers, and Dynamic Closures

A function pointer can point to a static nested function:

int function() fp;

void test() {
  static int a = 7;
  static int foo() { return a + 3; }

  fp = &foo;
}

void bar() {
  test();
  int i = fp();       // i is set to 10
}

A delegate can be set to a non-static nested function:

int delegate() dg;

void test() {
  int a = 7;
  int foo() { return a + 3; }

  dg = &foo;
  int i = dg(); // i is set to 10
}

The stack variables, however, are not valid once the function declaring them has exited, in the same manner that pointers to stack variables are not valid upon exit from a function:

int* bar() {
  int b;
  test();
  int i = dg(); // error, test.a no longer exists
  return &b;    // error, bar.b not valid after bar() exits
}

Delegates to non-static nested functions contain two pieces of data: the pointer to the stack frame of the lexically enclosing function (called the frame pointer) and the address of the function. This is analogous to struct/class non-static member function delegates consisting of a this pointer and the address of the member function. Both forms of delegates are interchangeable, and are actually the same type:

struct Foo {
  int a = 7;
  int bar() { return a; }
}

int foo(int delegate() dg) {
  return dg() + 1;
}

void test() {
  int x = 27;
  int abc() { return x; }
  Foo f;
  int i;

  i = foo(&abc);   // i is set to 28
  i = foo(&f.bar); // i is set to 8
}

This combining of the environment and the function is called a dynamic closure.

The .ptr property of a delegate will return the frame pointer value as a void*.

The .funcptr property of a delegate will return the function pointer value as a function type.

Future directions: Function pointers and delegates may merge into a common syntax and be interchangeable with each other.

Anonymous Functions and Anonymous Delegates

See FunctionLiterals.

main() Function

For console programs, main() serves as the entry point. It gets called after all the module initializers are run, and after any unittests are run. After it returns, all the module destructors are run. main() must be declared using one of the following forms:

void main() { ... }
void main(string[] args) { ... }
int main() { ... }
int main(string[] args) { ... }

Compile Time Function Execution (CTFE)

Functions which are both portable and free of side-effects can be executed at compile time. This is useful when constant folding algorithms need to include recursion and looping. Compile time function execution is subject to the following restrictions:

  1. the function source code must be available to the compiler. Functions which exist in the source code only as extern declarations cannot be executed at compile time
  2. executed expressions may not reference any global or local static variables
  3. asm statements are not permitted
  4. non-portable casts (eg, from int[] to float[]), including casts which depend on endianness, are not permitted. Casts between signed and unsigned types are permitted. Any pointer may be cast to void * and from void * back to its original type. Casting between pointer and non-pointer types is prohibited.
  5. C-style semantics on pointer arithmetic are strictly enforced.

    Pointer arithmetic is permitted only on pointers which point to static or dynamic array elements. Such pointers must point to an element of the array, or to the first element past the array. Ordered comparison (<, <=, >, >=) between pointers is permitted only between pointers which point to the same array. Pointer arithmetic is completely forbidden on pointers which are null, or which point to a non-array.

    Equality comparisons (==, !=, is, !is) are permitted between all pointers, without restriction.

  6. Non-recoverable errors (such as assert failures) do not throw exceptions; instead, they end interpretation immediately.

Note that the above restrictions apply only to expressions which are actually executed. For example:

static int y = 0;

int countTen(int x) {
  if (x > 10)
    ++y;
  return x;
}

static assert(countTen(6) == 6); // OK
static assert(countTen(12) == 12);  // invalid, modifies y.

In order to be executed at compile time, the function must appear in a context where it must be so executed, for example:

  • initialization of a static variable
  • dimension of a static array
  • argument for a template value parameter
template eval( A... ) {
  const typeof(A[0]) eval = A[0];
}

int square(int i) {
  return i * i;
}

void foo() {
  static j = square(3);     // compile time
  writefln(j);
  writefln(square(4));      // run time
  writefln(eval!(square(5))); // compile time
}

Executing functions at compile time can take considerably longer than executing it at run time. If the function goes into an infinite loop, it will hang at compile time (rather than hanging at run time).

Functions executed at compile time can give different results from run time in the following scenarios:

  • floating point computations may be done at a higher precision than run time
  • dependency on implementation defined order of evaluation
  • use of uninitialized variables

These are the same kinds of scenarios where different optimization settings affect the results.

String Mixins and Compile Time Function Execution

Any functions that execute at compile time must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. This means that the semantics of a function cannot depend on compile time values of the function. For example:

int foo(char[] s) {
  return mixin(s);
}

const int x = foo("1");

is illegal, because the runtime code for foo() cannot be generated. A function template would be the appropriate method to implement this sort of thing.


Operator Overloading

Last update Sun Dec 30 20:34:42 2012

Operator Overloading

Overloading is accomplished by interpreting specially named struct and class member functions as being implementations of unary and binary operators. No additional syntax is used.

  • Unary Operator Overloading
  • Binary Operator Overloading
  • Function Call Operator Overloading
  • Array Operator Overloading
  • Assignment Operator Overloading
  • Future Directions

Unary Operator Overloading

Overloadable Unary Operators
op | opfunc
-e | opNeg
+e | opPos
~e | opCom
e++ | opPostInc
e-- | opPostDec
cast(type)e | opCast

Given a unary overloadable operator op and its corresponding class or struct member function name opfunc, the syntax:

op a

where a is a class or struct object reference, is interpreted as if it was written as:

a.opfunc()

Overloading ++e and --e

Since ++e is defined to be semantically equivalent to (e += 1), the expression ++e is rewritten as (e += 1), and then checking for operator overloading is done. The situation is analogous for --e.

Examples

  1. class A { int opNeg(); }
A a;
-a;	// equivalent to a.opNeg();

  2. class A { int opNeg(int i); }
A a;
-a;	// equivalent to a.opNeg(), which is an error

Overloading cast(type)e

The member function e.opCast() is called, and the return value of opCast() is implicitly converted to type. Since functions cannot be overloaded based on return value, there can be only one opCast per struct or class. Overloading the cast operator does not affect implicit casts, it only applies to explicit casts.

struct A {
  int opCast() { return 28; }
}

void test() {
  A a;

  long i = cast(long)a; // i is set to 28L
  void* p = cast(void*)a; // error, cannot implicitly
                          // convert int to void*
  int j = a;  // error, cannot implicitly convert
              // A to int
}

Binary Operator Overloading

Overloadable Binary Operators
op | commutative? | opfunc | opfunc_r
+ | yes | opAdd | opAdd_r
- | no | opSub | opSub_r
* | yes | opMul | opMul_r
/ | no | opDiv | opDiv_r
% | no | opMod | opMod_r
& | yes | opAnd | opAnd_r
| | yes | opOr | opOr_r
^ | yes | opXor | opXor_r
<< | no | opShl | opShl_r
>> | no | opShr | opShr_r
>>> | no | opUShr | opUShr_r
~ | no | opCat | opCat_r
== | yes | opEquals | -
!= | yes | opEquals | -
< | yes | opCmp | -
<= | yes | opCmp | -
> | yes | opCmp | -
>= | yes | opCmp | -
= | no | opAssign | -
+= | no | opAddAssign | -
-= | no | opSubAssign | -
*= | no | opMulAssign | -
/= | no | opDivAssign | -
%= | no | opModAssign | -
&= | no | opAndAssign | -
|= | no | opOrAssign | -
^= | no | opXorAssign | -
<<= | no | opShlAssign | -
>>= | no | opShrAssign | -
>>>= | no | opUShrAssign | -
~= | no | opCatAssign | -
in | no | opIn | opIn_r

Given a binary overloadable operator op and its corresponding class or struct member function name opfunc and opfunc_r, and the syntax:

a op b
the following sequence of rules is applied, in order, to determine which form is used:
  1. The expression is rewritten as both:
    a.opfunc(b)
b.opfunc_r(a)
    If any a.opfunc or b.opfunc_r functions exist, then overloading is applied across all of them and the best match is used. If either exist, and there is no argument match, then it is an error.
  2. If the operator is commutative, then the following forms are tried:
    a.opfunc_r(b)
b.opfunc(a)
  3. If a or b is a struct or class object reference, it is an error.

Examples

  1. class A { int opAdd(int i); }
A a;
a + 1;	// equivalent to a.opAdd(1)
1 + a;	// equivalent to a.opAdd(1)

  2. class B { int opDiv_r(int i); }
B b;
1 / b;	// equivalent to b.opDiv_r(1)

  3. class A { int opAdd(int i); }
class B { int opAdd_r(A a); }
A a;
B b;
a + 1;	// equivalent to a.opAdd(1)
a + b;	// equivalent to b.opAdd_r(a)
b + a;	// equivalent to b.opAdd_r(a)

  4. class A { int opAdd(B b);  int opAdd_r(B b); }
class B { }
A a;
B b;
a + b;	// equivalent to a.opAdd(b)
b + a;	// equivalent to a.opAdd_r(b)

  5. class A { int opAdd(B b);  int opAdd_r(B b); }
class B { int opAdd_r(A a); }
A a;
B b;
a + b;	// ambiguous: a.opAdd(b) or b.opAdd_r(a)
b + a;	// equivalent to a.opAdd_r(b)

Overloading == and !=

Both operators use the opEquals() function. The expression (a == b) is rewritten as a.opEquals(b), and (a != b) is rewritten as !a.opEquals(b).

The member function opEquals() is defined as part of Object as:

int opEquals(Object o);

so that every class object has a default opEquals(). But every class definition which will be using == or != should expect to need to override opEquals. The parameter to the overriding function must be of type Object, not the type for the class.

Structs and unions (hereafter just called structs) can provide a member function:

int opEquals(S s)

or:

int opEquals(S* s)

where S is the struct name, to define how equality is determined.

If a struct has no opEquals function declared for it, a bit compare of the contents of the two structs is done to determine equality or inequality.

Note: Comparing a reference to a class object against null should be done as:

if (a is null)

and not as:

if (a == null)

The latter is converted to:

if (a.opEquals(null))

which will fail if opEquals() is a virtual function.

Overloading <, <=, > and >=

These comparison operators all use the opCmp() function. The expression (a op b) is rewritten as (a.opCmp(b) op 0). The commutative operation is rewritten as (0 op b.opCmp(a))

The member function opCmp() is defined as part of Object as:

int opCmp(Object o);

so that every class object has a opCmp().

opCmp for structs works analogously to opEquals for structs:

struct Pair {
  int a, b;
  int opCmp(Pair rhs) {
    if (a!=rhs.a)
      return a-rhs.a;
    return b-rhs.b;
  }
}

If a struct has no opCmp() function declared for it, attempting to compare two structs is an error.

Rationale

The reason for having both opEquals and opCmp is that:

  • Testing for equality can sometimes be a much more efficient operation than testing for less or greater than.
  • Having an opCmp defined in Object makes it possible to make associative arrays work generically for classes.
  • For some objects, testing for less or greater makes no sense. This is why Object.opCmp throws a runtime error. opCmp must be overridden in each class for which comparison makes sense.

The parameter to opEquals and opCmp for class definitions must be of type Object, rather than the type of the particular class, in order to override the Object.opEquals and Object.opCmp functions properly.

Function Call Operator Overloading f()

The function call operator, (), can be overloaded by declaring a function named opCall:

struct F {
  int opCall();
  int opCall(int x, int y, int z);
}

void test() {
  F f;
  int i;

  i = f();    // same as i = f.opCall();
  i = f(3,4,5);  // same as i = f.opCall(3,4,5);
}

In this way a struct or class object can behave as if it were a function.

Array Operator Overloading

Overloading Indexing a[i]

The array index operator, [], can be overloaded by declaring a function named opIndex with one or more parameters. Assignment to an array can be overloaded with a function named opIndexAssign with two or more parameters. The first parameter is the rvalue of the assignment expression.

struct A {
  int opIndex(size_t i1, size_t i2, size_t i3);
  int opIndexAssign(int value, size_t i1, size_t i2);
}

void test() {
  A a;
  int i;

  i = a[5,6,7]; // same as i = a.opIndex(5,6,7);
  a[i,3] = 7;   // same as a.opIndexAssign(7,i,3);
}

In this way a struct or class object can behave as if it were an array.

Note: Array index overloading currently does not work for the lvalue of an op=, ++, or -- operator.

Overloading Slicing a[] and a[i .. j]

Overloading the slicing operator means overloading expressions like a[] and a[i .. j]. This can be done by declaring a function named opSlice. Assignment to a slice can be done by declaring opSliceAssign.

class A {
  int opSlice();                   // overloads a[]
  int opSlice(size_t x, size_t y); // overloads a[i .. j]

  int opSliceAssign(int v); // overloads a[] = v
  int opSliceAssign(int v, size_t x, size_t y); // overloads a[i .. j] = v
}

void test() {
  A a = new A();
  int i;
  int v;

  i = a[];  // same as i = a.opSlice();
  i = a[3..4]; // same as i = a.opSlice(3,4);

  a[] = v;          // same as a.opSliceAssign(v);
  a[3..4] = v; // same as a.opSliceAssign(v,3,4);
}

Assignment Operator Overloading

The assignment operator = can be overloaded if the lvalue is a struct or class aggregate, and opAssign is a member function of that aggregate.

The assignment operator cannot be overloaded for rvalues that can be implicitly cast to the lvalue type. Furthermore, the following parameter signatures for opAssign are not allowed:

opAssign(...)
opAssign(T)
opAssign(T, ...)
opAssign(T ...)
opAssign(T, U = defaultValue, etc.)

where T is the same type as the aggregate type A, is implicitly convertible to A, or if A is a struct and T is a pointer to a type that is implicitly convertible to A.

Future Directions

The operators ! && || ?: and a few others will likely never be overloadable.


Templates

Last update Sun Dec 30 20:34:42 2012

Templates

I think that I can safely say that nobody understands template mechanics. -- Richard Deyman

Templates are D's approach to generic programming. Templates are defined with a TemplateDeclaration:

TemplateDeclaration:
    template TemplateIdentifier ( TemplateParameterList )
        { DeclDefs }

TemplateIdentifier:
    Identifier

TemplateParameterList:
    TemplateParameter
    TemplateParameter , TemplateParameterList

TemplateParameter:
    TemplateTypeParameter
    TemplateValueParameter
    TemplateAliasParameter
    TemplateTupleParameter

The body of the TemplateDeclaration must be syntactically correct even if never instantiated. Semantic analysis is not done until instantiated. A template forms its own scope, and the template body can contain classes, structs, types, enums, variables, functions, and other templates.

Template parameters can be types, values, symbols, or tuples. Types can be any type. Value parameters must be of an integral type, floating point type, or string type and specializations for them must resolve to an integral constant, floating point constant, null, or a string literal. Symbols can be any non-local symbol. Tuples are a sequence of 0 or more types, values or symbols.

Template parameter specializations constrain the values or types the TemplateParameter can accept.

Template parameter defaults are the value or type to use for the TemplateParameter in case one is not supplied.

Explicit Template Instantiation

Templates are explicitly instantiated with:

TemplateInstance:
    TemplateIdentifier !( TemplateArgumentList )

TemplateArgumentList:
    TemplateArgument
    TemplateArgument , TemplateArgumentList

TemplateArgument:
    Type
    AssignExpression
    Symbol

Symbol:
    SymbolTail
    . SymbolTail

SymbolTail:
    Identifier
    Identifier . SymbolTail
    TemplateInstance
    TemplateInstance . SymbolTail

Once instantiated, the declarations inside the template, called the template members, are in the scope of the TemplateInstance:

template TFoo(T) { alias T* t; }
...
TFoo!(int).t x; // declare x to be of type int*

A template instantiation can be aliased:

template TFoo(T) { alias T* t; }
alias TFoo!(int) abc;
abc.t x;        // declare x to be of type int*

Multiple instantiations of a TemplateDeclaration with the same TemplateArgumentList, before implicit conversions, all will refer to the same instantiation. For example:

template TFoo(T) { T f; }
alias TFoo!(int) a;
alias TFoo!(int) b;
...
a.f = 3;
assert(b.f == 3);  // a and b refer to the same instance of TFoo

This is true even if the TemplateInstances are done in different modules.

Even if template arguments are implicitly converted to the same template parameter type, they still refer to different instances:

struct TFoo(int x) { }
static assert(is(TFoo!(3) == TFoo!(2 + 1))); // 3 and 2+1 are both 3 of type int
static assert(!is(TFoo!(3) == TFoo!(3u)));   // 3u and 3 are different types

If multiple templates with the same TemplateIdentifier are declared, they are distinct if they have a different number of arguments or are differently specialized.

For example, a simple generic copy template would be:

template TCopy(T) {
  void copy(out T to, T from) {
    to = from;
  }
}

To use the template, it must first be instantiated with a specific type:

int i;
TCopy!(int).copy(i, 3);

Instantiation Scope

TemplateInstantances are always performed in the scope of where the TemplateDeclaration is declared, with the addition of the template parameters being declared as aliases for their deduced types.

For example:

module a
template TFoo(T) { void bar() { func(); } }
module b
import a;

void func() { }
alias TFoo!(int) f; // error: func not defined in module a

and:

module a
template TFoo(T) { void bar() { func(1); } }
void func(double d) { }
module b
import a;

void func(int i) { }
alias TFoo!(int) f;
...
f.bar();  // will call a.func(double)

TemplateParameter specializations and default values are evaluated in the scope of the TemplateDeclaration.

Argument Deduction

The types of template parameters are deduced for a particular template instantiation by comparing the template argument with the corresponding template parameter.

For each template parameter, the following rules are applied in order until a type is deduced for each parameter:

  1. If there is no type specialization for the parameter, the type of the parameter is set to the template argument.
  2. If the type specialization is dependent on a type parameter, the type of that parameter is set to be the corresponding part of the type argument.
  3. If after all the type arguments are examined there are any type parameters left with no type assigned, they are assigned types corresponding to the template argument in the same position in the TemplateArgumentList.
  4. If applying the above rules does not result in exactly one type for each template parameter, then it is an error.

For example:

template TFoo(T) { }
alias TFoo!(int) Foo1;     // (1) T is deduced to be int
alias TFoo!(char*) Foo2;   // (1) T is deduced to be char*

template TBar(T : T*) { }
alias TBar!(char*) Foo3;   // (2) T is deduced to be char

template TAbc(D, U : D[]) { }
alias TAbc!(int, int[]) Bar1;  // (2) D is deduced to be int, U is int[]
alias TAbc!(char, int[]) Bar2; // (4) error, D is both char and int

template TDef(D : E*, E) { }
alias TDef!(int*, int) Bar3; // (1) E is int
                             // (3) D is int*

Deduction from a specialization can provide values for more than one parameter:

template Foo(T: T[U], U) {
  ...
}

Foo!(int[long])  // instantiates Foo with T set to int, U set to long

When considering matches, a class is considered to be a match for any super classes or interfaces:

class A { }
class B : A { }

template TFoo(T : A) { }
alias TFoo!(B) Foo4;    // (3) T is B

template TBar(T : U*, U : A) { }
alias TBar!(B*, B) Foo5; // (2) T is B*
                         // (3) U is B

Template Type Parameters

TemplateTypeParameter:
    Identifier
    Identifier TemplateTypeParameterSpecialization
    Identifier TemplateTypeParameterDefault
    Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault

TemplateTypeParameterSpecialization:
     : Type

TemplateTypeParameterDefault:
     = Type

Specialization

Templates may be specialized for particular types of arguments by following the template parameter identifier with a : and the specialized type. For example:

template TFoo(T)        { ... } // #1
template TFoo(T : T[])  { ... } // #2
template TFoo(T : char) { ... } // #3
template TFoo(T,U,V)    { ... } // #4

alias TFoo!(int) foo1;         // instantiates #1
alias TFoo!(double[]) foo2;    // instantiates #2 with T being double
alias TFoo!(char) foo3;        // instantiates #3
alias TFoo!(char, int) fooe;   // error, number of arguments mismatch
alias TFoo!(char, int, int) foo4; // instantiates #4

The template picked to instantiate is the one that is most specialized that fits the types of the TemplateArgumentList. Determine which is more specialized is done the same way as the C++ partial ordering rules. If the result is ambiguous, it is an error.

Template Value Parameters

TemplateValueParameter:
    BasicType Declarator
    BasicType Declarator TemplateValueParameterSpecialization
    BasicType Declarator TemplateValueParameterDefault
    BasicType Declarator TemplateValueParameterSpecialization TemplateValueParameterDefault

TemplateValueParameterSpecialization:
    : ConditionalExpression

TemplateValueParameterDefault:

    = AssignExpression

Template value parameter types can be any type which can be statically initialized at compile time. Template value arguments can be integer values, floating point values, nulls, string values, array literals of template value arguments, associative array literals of template value arguments, or struct literals of template value arguments.

template foo(string s) {
  string bar() { return s ~ " betty"; }
}

void main() {
  writefln("%s", foo!("hello").bar()); // prints: hello betty
}

This example of template foo has a value parameter that is specialized for 10:

template foo(U : int, int T : 10) {
  U x = T;
}

void main() {
  assert(foo!(int, 10).x == 10);
}

Template Alias Parameters

TemplateAliasParameter:
    alias Identifier TemplateAliasParameterSpecializationopt TemplateAliasParameterDefaultopt
    alias BasicType Declarator TemplateAliasParameterSpecializationopt TemplateAliasParameterDefaultopt

TemplateAliasParameterSpecialization:
    : Type
    : ConditionalExpression

TemplateAliasParameterDefault:
    = Type
    = ConditionalExpression

Alias parameters enable templates to be parameterized with any type of D symbol, including global names, local names, typedef names, module names, template names, and template instance names.

  • Global names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

void test() {
  alias Foo!(x) bar;
  *bar.p = 3;       // set x to 3
  static int y;
  alias Foo!(y) abc;
  *abc.p = 3;       // set y to 3
}
  • Type names
    class Foo {
  static int p;
}

template Bar(alias T) {
  alias T.p q;
}

void test() {
  alias Bar!(Foo) bar;
  bar.q = 3;  // sets Foo.p to 3
}
  • Module names
    import std.string;

template Foo(alias X) {
  alias X.toString y;
}

void test() {
  alias Foo!(std.string) bar;
  bar.y(3);   // calls std.string.toString(3)
}
  • Template names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

template Bar(alias T) {
  alias T!(x) abc;
}

void test() {
  alias Bar!(Foo) bar;
  *bar.abc.p = 3;  // sets x to 3
}
  • Template alias names
    int x;

template Foo(alias X) {
  static int* p = &X;
}

template Bar(alias T) {
  alias T.p q;
}

void test() {
  alias Foo!(x) foo;
  alias Bar!(foo) bar;
  *bar.q = 3;  // sets x to 3
}

Template Tuple Parameters

TemplateTupleParameter:
        Identifier ...

If the last template parameter in the TemplateParameterList is declared as a TemplateTupleParameter, it is a match with any trailing template arguments. The sequence of arguments form a Tuple. A Tuple is not a type, an expression, or a symbol. It is a sequence of any mix of types, expressions or symbols.

A Tuple whose elements consist entirely of types is called a TypeTuple. A Tuple whose elements consist entirely of expressions is called an ExpressionTuple.

A Tuple can be used as an argument list to instantiate another template, or as the list of parameters for a function.

template Print(A ...) {
  void print() {
    writefln("args are ", A);
  }
}

template Write(A ...) {
  void write(A a) // A is a TypeTuple
                  // a is an ExpressionTuple
  {
    writefln("args are ", a);
  }
}

void main() {
  Print!(1,'a',6.8).print();                    // prints: args are 1a6.8
  Write!(int, char, double).write(1, 'a', 6.8); // prints: args are 1a6.8
}

Template tuples can be deduced from the types of the trailing parameters of an implicitly instantiated function template:

template Foo(T, R...) {
  void Foo(T t, R r) {
    writefln(t);
    static if (r.length) // if more arguments
      Foo(r);            // do the rest of the arguments
  }
}

void main() {
  Foo(1, 'a', 6.8);
}

prints:

1
a
6.8

The tuple can also be deduced from the type of a delegate or function parameter list passed as a function argument:

import std.stdio;

/* R is return type
 * A is first argument type
 * U is TypeTuple of rest of argument types
 */
R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg)
{
  struct Foo
  {
    typeof(dg) dg_m;
    typeof(arg) arg_m;

    R bar(U u)
    {
      return dg_m(arg_m, u);
    }
  }

  Foo* f = new Foo;
  f.dg_m = dg;
  f.arg_m = arg;
  return &f.bar;
}

void main()
{
  int plus(int x, int y, int z)
  {
    return x + y + z;
  }

  auto plus_two = Curry(&plus, 2);
  writefln("%d", plus_two(6, 8)); // prints 16
}

The number of elements in a Tuple can be retrieved with the .length property. The nth element can be retrieved by indexing the Tuple with [n], and sub tuples can be created with the slicing syntax.

Tuples are static compile time entities, there is no way to dynamically change, add, or remove elements.

If both a template with a tuple parameter and a template without a tuple parameter exactly match a template instantiation, the template without a TemplateTupleParameter is selected.

Template Parameter Default Values

Trailing template parameters can be given default values:

template Foo(T, U = int) { ... }
Foo!(uint,long); // instantiate Foo with T as uint, and U as long
Foo!(uint);      // instantiate Foo with T as uint, and U as int

template Foo(T, U = T*) { ... }
Foo!(uint);      // instantiate Foo with T as uint, and U as uint*

Implicit Template Properties

If a template has exactly one member in it, and the name of that member is the same as the template name, that member is assumed to be referred to in a template instantiation:

template Foo(T) {
  T Foo; // declare variable Foo of type T
}

void test() {
  Foo!(int) = 6; // instead of Foo!(int).Foo
}

Template Constructors

TemplatedConstructor:
    this ( TemplateParameterList ) Parameters Constraintopt FunctionBody

Templates can be used to form constructors for classes.

Class Templates

ClassTemplateDeclaration:
    class Identifier ( TemplateParameterList ) Constraintopt BaseClassListopt ClassBody

If a template declares exactly one member, and that member is a class with the same name as the template:

template Bar(T) {
  class Bar {
    T member;
  }
}

then the semantic equivalent, called a ClassTemplateDeclaration can be written as:

class Bar(T) {
  T member;
}

Struct, Union, and Interface Templates

StructTemplateDeclaration:
    struct Identifier ( TemplateParameterList )  StructBody

UnionTemplateDeclaration:
    union Identifier ( TemplateParameterList )  StructBody

InterfaceTemplateDeclaration:
    interface Identifier ( TemplateParameterList )  BaseInterfaceListopt InterfaceBody

Analogously to class templates, struct, union and interfaces can be transformed into templates by supplying a template parameter list.

Function Templates

If a template declares exactly one member, and that member is a function with the same name as the template, it is a function template declaration. Alternatively, a function template declaration is a function declaration with a TemplateParameterList immediately preceding the Parameters.

A function template to compute the square of type T is:

T Square(T)(T t) {
  return t * t;
}

Function templates can be explicitly instantiated with a !(TemplateArgumentList):

writefln("The square of %s is %s", 3, Square!(int)(3));

or implicitly, where the TemplateArgumentList is deduced from the types of the function arguments:

writefln("The square of %s is %s", 3, Square(3));  // T is deduced to be int

If there are fewer arguments supplied in the TemplateArgumentList than parameters in the TemplateParameterList, the arguments fulfill parameters from left to right, and the rest of the parameters are then deduced from the function arguments.

Function template type parameters that are to be implicitly deduced may not have specializations:

void Foo(T : T*)(T t) { ... }

int x,y;
Foo!(int*)(x);   // ok, T is not deduced from function argument
Foo(&y);         // error, T has specialization

Template arguments not implicitly deduced can have default values:

void Foo(T, U=T*)(T t) { U p; ... }

int x;
Foo(&x);    // T is int, U is int*

Function Templates with Auto Ref Parameters

An auto ref function template parameter becomes a ref parameter if its corresponding argument is an lvalue, otherwise it becomes a value parameter:

int foo(T...)(auto ref T x) {
  int result;

  foreach (i, v; x)
  {
    if (v == 10)
      assert(__traits(isRef, x[i]));
    else
      assert(!__traits(isRef, x[i]));
    result += v;
  }
  return result;
}

void main() {
  int y = 10;
  int r;
  r = foo(8);       // returns 8
  r = foo(y);       // returns 10
  r = foo(3, 4, y); // returns 17
  r = foo(4, 5, y); // returns 19
  r = foo(y, 6, y); // returns 26
}

Auto ref parameters can be combined with auto ref return attributes:

auto ref min(T, U)(auto ref T lhs, auto ref U rhs)
{
  return lhs > rhs ? rhs : lhs;
}

void main()
{
  int x = 7, y = 8;
  int i;

  i = min(4, 3);     // returns 3
  i = min(x, y);     // returns 7
  min(x, y) = 10;    // sets x to 10
  static assert(!__traits(compiles, min(3, y) = 10));
  static assert(!__traits(compiles, min(y, 3) = 10));
}

Recursive Templates

Template features can be combined to produce some interesting effects, such as compile time evaluation of non-trivial functions. For example, a factorial template can be written:

template factorial(int n : 1) {
  enum { factorial = 1 }
}

template factorial(int n) {
  enum { factorial = n* factorial!(n-1) }
}

void test() {
  writefln("%s", factorial!(4)); // prints 24
}

Limitations

Templates cannot be used to add non-static members or virtual functions to classes. For example:

class Foo {
  template TBar(T) {
    T xx;               // becomes a static member of Foo
    int func(T) { ... } // non-virtual

    static T yy;                        // Ok
    static int func(T t, int y) { ... } // Ok
  }
}

Templates cannot be declared inside functions.

Templates cannot add functions to interfaces:

interface TestInterface { void tpl(T)(); }   // error


Mixins

Last update Sun Dec 30 20:34:44 2012

Template Mixins

A TemplateMixin takes an arbitrary set of declarations from the body of a TemplateDeclaration and inserts them into the current context.
TemplateMixinDeclaration:
     template TemplateIdentifier ( TemplateParameterList )
        { DeclDefs }

TemplateMixin:
    mixin TemplateIdentifier ;
    mixin TemplateIdentifier MixinIdentifier ;
    mixin TemplateIdentifier !( TemplateArgumentList ) ;
    mixin TemplateIdentifier !( TemplateArgumentList ) MixinIdentifier ;

MixinIdentifier:
    Identifier

A TemplateMixin can occur in declaration lists of modules, classes, structs, unions, and as a statement. The TemplateIdentifier refers to a TemplateDeclaration. If the TemplateDeclaration has no parameters, the mixin form that has no !(TemplateArgumentList) can be used.

Unlike a template instantiation, a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined. It is analogous to cutting and pasting the body of the template into the location of the mixin. It is useful for injecting parameterized ‘boilerplate’ code, as well as for creating templated nested functions, which is not possible with template instantiations.

 template Foo() {
  int x = 5;
}

mixin Foo;

struct Bar {
  mixin Foo;
}

void test() {
  writefln("x = %d", x);  // prints 5
  {
    Bar b;
    int x = 3;

    writefln("b.x = %d", b.x); // prints 5
    writefln("x = %d", x);     // prints 3
    {
      mixin Foo;
      writefln("x = %d", x);   // prints 5
      x = 4;
      writefln("x = %d", x);   // prints 4
    }
    writefln("x = %d", x);     // prints 3
  }
  writefln("x = %d", x);       // prints 5
}
Mixins can be parameterized:
 template Foo(T) {
  T x = 5;
}

mixin Foo!(int);           // create x of type int
Mixins can add virtual functions to a class:
 template Foo() {
  void func() { writefln("Foo.func()"); }
}

class Bar {
  mixin Foo;
}

class Code : Bar {
  void func() { writefln("Code.func()"); }
}

void test() {
  Bar b = new Bar();
  b.func();      // calls Foo.func()

  b = new Code();
  b.func();      // calls Code.func()
}
Mixins are evaluated in the scope of where they appear, not the scope of the template declaration:
int y = 3;

 template Foo() {
  int abc() { return y; }
}

void test() {
  int y = 8;
  mixin Foo; // local y is picked up, not global y
  assert(abc() == 8);
}
Mixins can parameterize symbols using alias parameters:
 template Foo(alias b) {
  int abc() { return b; }
}

void test() {
  int y = 8;
  mixin Foo!(y);
  assert(abc() == 8);
}
This example uses a mixin to implement a generic Duff's device for an arbitrary statement (in this case, the arbitrary statement is in bold). A nested function is generated as well as a delegate literal, these can be inlined by the compiler:
 template duffs_device(alias id1, alias id2, alias s)
{
  void duff_loop()
  {
    if (id1 < id2)
    {
      typeof(id1) n = (id2 - id1 + 7) / 8;
      switch ((id2 - id1) % 8)
      {
        case 0: do { s();
        case 7:      s();
        case 6:      s();
        case 5:      s();
        case 4:      s();
        case 3:      s();
        case 2:      s();
        case 1:      s();
                } while (--n > 0);
        }
    }
  }
}

void foo() { writefln("foo"); }

void test() {
  int i = 1;
  int j = 11;

  mixin duffs_device!(i, j, delegate { foo(); } );
  duff_loop();  // executes foo() 10 times
}

Mixin Scope

The declarations in a mixin are ‘imported’ into the surrounding scope. If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one:
int x = 3;

 template Foo() {
  int x = 5;
  int y = 5;
}

mixin Foo;
int y = 3;

void test() {
  writefln("x = %d", x);  // prints 3
  writefln("y = %d", y);  // prints 3
}
If two different mixins are put in the same scope, and each define a declaration with the same name, there is an ambiguity error when the declaration is referenced:
 template Foo() {
  int x = 5;
  void func(int x) { }
}

 template Bar() {
  int x = 4;
  void func() { }
}

mixin Foo;
mixin Bar;

void test() {
  writefln("x = %d", x); // error, x is ambiguous
  func();             // error, func is ambiguous
}

The call to func() is ambiguous because Foo.func and Bar.func are in different scopes.

If a mixin has a MixinIdentifier, it can be used to disambiguate:

int x = 6;

 template Foo() {
  int x = 5;
  int y = 7;
  void func() { }
}

 template Bar() {
  int x = 4;
  void func() { }
}

mixin Foo F;
mixin Bar B;

void test() {
  writefln("y = %d", y);     // prints 7
  writefln("x = %d", x);     // prints 6
  writefln("F.x = %d", F.x); // prints 5
  writefln("B.x = %d", B.x); // prints 4
  F.func();                  // calls Foo.func
  B.func();                  // calls Bar.func
}

Alias declarations can be used to overload together functions declared in different mixins:

 template Foo() {
  void func(int x) {  }
}

 template Bar() {
  void func() {  }
}

mixin Foo!() F;
mixin Bar!() B;

alias F.func func;
alias B.func func;

void main() {
  func();  // calls B.func
  func(1); // calls F.func
}

A mixin has its own scope, even if a declaration is overridden by the enclosing one:

int x = 4;

 template Foo() {
  int x = 5;
  int bar() { return x; }
}

mixin Foo;

void test() {
  writefln("x = %d", x);         // prints 4
  writefln("bar() = %d", bar()); // prints 5
}


Contract Programming

Last update Sun Dec 30 20:34:42 2012

Contract Programming

Contracts are a breakthrough technique to reduce the programming effort for large projects. Contracts are the concept of preconditions, postconditions, errors, and invariants. Contracts can be done in C++ without modification to the language, but the result is clumsy and inconsistent.

Building contract support into the language makes for:

  1. a consistent look and feel for the contracts
  2. tool support
  3. it's possible the compiler can generate better code using information gathered from the contracts
  4. easier management and enforcement of contracts
  5. handling of contract inheritance
Contracts make D bug resistant The idea of a contract is simple - it's just an expression that must evaluate to true. If it does not, the contract is broken, and by definition, the program has a bug in it. Contracts form part of the specification for a program, moving it from the documentation to the code itself. And as every programmer knows, documentation tends to be incomplete, out of date, wrong, or non-existent. Moving the contracts into the code makes them verifiable against the program.

Assert Contract

The most basic contract is the assert. An assert inserts a checkable expression into the code, and that expression must evaluate to true:
assert(expression);
C programmers will find it familiar. Unlike C, however, an assert in function bodies works by throwing an AssertError, which can be caught and handled. Catching the contract violation is useful when the code must deal with errant uses by other code, when it must be failure proof, and as a useful tool for debugging.

Pre and Post Contracts

The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has. The syntax is:
in
{
    ...contract preconditions...
}
out (result)
{
    ...contract postconditions...
}
body
{
    ...code...
}
By definition, if a pre contract fails, then the body received bad parameters. An AssertError is thrown. If a post contract fails, then there is a bug in the body. An AssertError is thrown.

Either the in or the out clause can be omitted. If the out clause is for a function body, the variable result is declared and assigned the return value of the function. For example, let's implement a square root function:

long square_root(long x)
    in
    {
    assert(x >= 0);
    }
    out (result)
    {
    assert((result * result) <= x && (result+1) * (result+1) >= x);
    }
    body
    {
    return cast(long)std.math.sqrt(cast(real)x);
    }
The assert's in the in and out bodies are called contracts. Any other D statement or expression is allowed in the bodies, but it is important to ensure that the code has no side effects, and that the release version of the code will not depend on any effects of the code. For a release build of the code, the in and out code is not inserted.

If the function returns a void, there is no result, and so there can be no result declaration in the out clause. In that case, use:

void func()
   out
   {
    ...contracts...
   }
   body
   {
    ...
   }
In an out statement, result is initialized and set to the return value of the function.

In, Out and Inheritance

If a function in a derived class overrides a function in its super class, then only one of the in contracts of the function and its base functions must be satisfied. Overriding functions then becomes a process of loosening the in contracts.

A function without an in contract means that any values of the function parameters are allowed. This implies that if any function in an inheritance hierarchy has no in contract, then in contracts on functions overriding it have no useful effect.

Conversely, all of the out contracts needs to be satisfied, so overriding functions becomes a processes of tightening the out contracts.

Class Invariants

Class invariants are used to specify characteristics of a class that always must be true (except while executing a member function). They are described in Classes.

References

Contracts Reading List
Adding Contracts to Java


Conditional Compilation

Last update Sun Dec 30 20:34:42 2012

Conditional Compilation

Conditional compilation is the process of selecting which code to compile and which code to not compile. (In C and C++, conditional compilation is done with the preprocessor directives #if / #else / #endif.)

ConditionalDeclaration:
    Condition CCDeclarationBlock
    Condition CCDeclarationBlock else CCDeclarationBlock
    Condition : Declarations

CCDeclarationBlock:
    Declaration
    { Declarations }
    { }

Declarations:
    Declaration
    Declaration Declarations

ConditionalStatement:
    Condition NoScopeNonEmptyStatement
    Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement

If the Condition is satisfied, then the following CCDeclarationBlock or Statement is compiled in. If it is not satisfied, the CCDeclarationBlock or Statement after the optional else is compiled in.

Any CCDeclarationBlock or Statement that is not compiled in still must be syntactically correct.

No new scope is introduced, even if the CCDeclarationBlock or Statement is enclosed by { }.

ConditionalDeclarations and ConditionalStatements can be nested.

The StaticAssert can be used to issue errors at compilation time for branches of the conditional compilation that are errors.

Condition comes in the following forms:

Condition:
    VersionCondition
    DebugCondition
    StaticIfCondition

Version Condition

VersionCondition:
    version ( IntegerLiteral )
    version ( Identifier )

Versions enable multiple versions of a module to be implemented with a single source file.

The VersionCondition is satisfied if the IntegerLiteral is greater than or equal to the current version level, or if Identifier matches a version identifier.

The version level and version identifier can be set on the command line by the -version switch or in the module itself with a VersionSpecification, or they can be predefined by the compiler.

Version identifiers are in their own unique name space, they do not conflict with debug identifiers or other symbols in the module. Version identifiers defined in one module have no influence over other imported modules.

int k;
version (Demo) // compile in this code block for the demo version
{ int i;
  int k;    // error, k already defined

  i = 3;
}
x = i;      // uses the i declared above

version (X86)
{
  ... // implement custom inline assembler version
}
else
{
  ... // use default, but slow, version
}

Version Specification

VersionSpecification:
    version = Identifier ;
    version = IntegerLiteral ;

The version specification makes it straightforward to group a set of features under one major version, for example:

version (ProfessionalEdition)
{
  version = FeatureA;
  version = FeatureB;
  version = FeatureC;
}
version (HomeEdition)
{
  version = FeatureA;
}
...
version (FeatureB)
{
  ... implement Feature B ...
}

Version identifiers or levels may not be forward referenced:

version (Foo)
{
  int x;
}
version = Foo;	// error, Foo already used

VersionSpecifications may only appear at module scope.

While the debug and version conditions superficially behave the same, they are intended for very different purposes. Debug statements are for adding debug code that is removed for the release version. Version statements are to aid in portability and multiple release versions.

Here's an example of a full version as opposed to a demo version:

class Foo {
  int a, b;

  version(full)
  {
    int extrafunctionality()
    {
      ...
      return 1;  // extra functionality is supported
    }
  }
  else // demo
  {
    int extrafunctionality()
    {
      return 0;  // extra functionality is not supported
    }
  }
}
Various different version builds can be built with a parameter to version:
version(n) // add in version code if version level is &gt;= n
{
   ... version code ...
}

version(identifier) // add in version code if version
                         // keyword is identifier
{
   ... version code ...
}

These are presumably set by the command line as -version=n and -version=identifier.

Predefined Versions

Several environmental version identifiers and identifier name spaces are predefined for consistent usage. Version identifiers do not conflict with other identifiers in the code, they are in a separate name space. Predefined version identifiers are global, i.e. they apply to all modules being compiled and imported.

Predefined Version Identifiers
Version Identifier | Description
DigitalMars | DMD (Digital Mars D) is the compiler
GNU | GDC (GNU D Compiler) is the compiler
LDC | LDC (LLVM D Compiler) is the compiler
SDC | SDC (Stupid D Compiler) is the compiler
D_NET | D.NET is the compiler
Windows | Microsoft Windows systems
Win32 | Microsoft 32-bit Windows systems
Win64 | Microsoft 64-bit Windows systems
linux | All Linux systems
OSX | Mac OS X
FreeBSD | FreeBSD
OpenBSD | OpenBSD
BSD | All other BSDs
Solaris | Solaris
Posix | All POSIX systems (includes Linux, FreeBSD, OS X, Solaris, etc.)
AIX | IBM Advanced Interactive eXecutive OS
SkyOS | The SkyOS operating system
SysV3 | System V Release 3
SysV4 | System V Release 4
Hurd | GNU Hurd
Cygwin | The Cygwin environment
MinGW | The MinGW environment
X86 | Intel and AMD 32-bit processors
X86_64 | AMD and Intel 64-bit processors
ARM | The Advanced RISC Machine architecture (32-bit)
PPC | The PowerPC architecture, 32-bit
PPC64 | The PowerPC architecture, 64-bit
IA64 | The Itanium architecture (64-bit)
MIPS | The MIPS architecture, 32-bit
MIPS64 | The MIPS architecture, 64-bit
SPARC | The SPARC architecture, 32-bit
SPARC64 | The SPARC architecture, 64-bit
S390 | The System/390 architecture, 32-bit
S390X | The System/390X architecture, 64-bit
HPPA | The HP PA-RISC architecture, 32-bit
HPPA64 | The HP PA-RISC architecture, 64-bit
SH | The SuperH architecture, 32-bit
SH64 | The SuperH architecture, 64-bit
Alpha | The Alpha architecture
LittleEndian | Byte order, least significant first
BigEndian | Byte order, most significant first
D_Coverage | Code coverage analysis instrumentation (command line switch -cov) is being generated
D_Ddoc | Ddoc documentation (command line switch -D) is being generated
D_InlineAsm_X86 | Inline assembler for X86 is implemented
D_InlineAsm_X86_64 | Inline assembler for X86-64 is implemented
D_LP64 | Pointers are 64 bits (command line switch -m64)
D_PIC | Position Independent Code (command line switch -fPIC) is being generated
none | Never defined; used to just disable a section of code
all | Always defined; used as the opposite of none

The following identifiers are defined, but are deprecated:

Predefined Version Identifiers
Version Identifier | Description
darwin | The Darwin operating system; use OSX instead

Others will be added as they make sense and new implementations appear.

It is inevitable that the D language will evolve over time. Therefore, the version identifier namespace beginning with "D_" is reserved for identifiers indicating D language specification or new feature conformance.

Furthermore, predefined version identifiers from this list cannot be set from the command line or from version statements. (This prevents things like both Windows and linux being simultaneously set.)

Compiler vendor specific versions can be predefined if the trademarked vendor identifier prefixes it, as in:

version(DigitalMars_funky_extension)
{
    ...
}

It is important to use the right version identifier for the right purpose. For example, use the vendor identifier when using a vendor specific feature. Use the operating system identifier when using an operating system specific feature, etc.

Debug Condition

DebugCondition:
    debug
    debug ( IntegerLiteral )
    debug ( Identifier )

Two versions of programs are commonly built, a release build and a debug build. The debug build includes extra error checking code, test harnesses, pretty-printing code, etc. The debug statement conditionally compiles in its statement body. It is D's way of what in C is done with #ifdef DEBUG / #endif pairs.

The debug condition is satisfied when the -debug switch is thrown on the compiler.

The debug ( IntegerLiteral ) condition is satisfied when the debug level is >= IntegerLiteral.

The debug ( Identifier ) condition is satisfied when the debug identifier matches Identifier.

class Foo {
  int a, b;
 debug:
  int flag;
}

Debug Specification

DebugSpecification:
    debug = Identifier ;
    debug = IntegerLiteral ;

Debug identifiers and levels are set either by the command line switch -debug or by a DebugSpecification.

Debug specifications only affect the module they appear in, they do not affect any imported modules. Debug identifiers are in their own namespace, independent from version identifiers and other symbols.

It is illegal to forward reference a debug specification:

debug (foo) writefln("Foo");
debug = foo;	// error, foo used before set

DebugSpecifications may only appear at module scope.

Various different debug builds can be built with a parameter to debug:

debug(IntegerLiteral) { }    // add in debug code if debug level is &gt;= IntegerLiteral
debug(identifier) { } // add in debug code if debug keyword is identifier

These are presumably set by the command line as -debug=n and -debug=identifier.

Static If Condition

StaticIfCondition:
    static if ( AssignExpression )

AssignExpression is implicitly converted to a boolean type, and is evaluated at compile time. The condition is satisfied if it evaluates to true. It is not satisfied if it evaluates to false.

It is an error if AssignExpression cannot be implicitly converted to a boolean type or if it cannot be evaluated at compile time.

StaticIfConditions can appear in module, class, template, struct, union, or function scope. In function scope, the symbols referred to in the AssignExpression can be any that can normally be referenced by an expression at that point.

const int i = 3;
int j = 4;

static if (i == 3)	// ok, at module scope
    int x;

class C {
  const int k = 5;

  static if (i == 3) // ok
    int x;
  else
    long x;

  static if (j == 3) // error, j is not a constant
    int y;

  static if (k == 5) // ok, k is in current scope
    int z;
}

template INT(int i) {
  static if (i == 32)
    alias int INT;
  else static if (i == 16)
    alias short INT;
  else
    static assert(0); // not supported
}

INT!(32) a;  // a is an int
INT!(16) b;  // b is a short
INT!(17) c;  // error, static assert trips

A StaticIfConditional condition differs from an IfStatement in the following ways:

  1. It can be used to conditionally compile declarations, not just statements.
  2. It does not introduce a new scope even if { } are used for conditionally compiled statements.
  3. For unsatisfied conditions, the conditionally compiled code need only be syntactically correct. It does not have to be semantically correct.
  4. It must be evaluatable at compile time.

Static Assert

StaticAssert:
    static assert ( AssignExpression );
    static assert ( AssignExpression , AssignExpression );

AssignExpression is evaluated at compile time, and converted to a boolean value. If the value is true, the static assert is ignored. If the value is false, an error diagnostic is issued and the compile fails.

Unlike AssertExpressions, StaticAsserts are always checked and evaluted by the compiler unless they appear in an unsatisfied conditional.

void foo() {
  if (0)
  {
    assert(0);  // never trips
    static assert(0); // always trips
  }
  version (BAR)
  {
  }
  else
  {
    static assert(0); // trips when version BAR is not defined
  }
}

StaticAssert is useful tool for drawing attention to conditional configurations not supported in the code.

The optional second AssignExpression can be used to supply additional information, such as a text string, that will be printed out along with the error diagnostic.


Errors

Last update Sun Dec 30 20:34:42 2012

Error Handling in D

I came, I coded, I crashed. -- Julius C'ster

All programs have to deal with errors. Errors are unexpected conditions that are not part of the normal operation of a program. Examples of common errors are:
  • Out of memory.
  • Out of disk space.
  • Invalid file name.
  • Attempting to write to a read-only file.
  • Attempting to read a non-existent file.
  • Requesting a system service that is not supported.

The Error Handling Problem

The traditional C way of detecting and reporting errors is not traditional, it is ad-hoc and varies from function to function, including:
  • Returning a NULL pointer.
  • Returning a 0 value.
  • Returning a non-zero error code.
  • Requiring errno to be checked.
  • Requiring that a function be called to check if the previous function failed.
To deal with these possible errors, tedious error handling code must be added to each function call. If an error happened, code must be written to recover from the error, and the error must be reported to the user in some user friendly fashion. If an error cannot be handled locally, it must be explicitly propagated back to its caller. The long list of errno values needs to be converted into appropriate text to be displayed. Adding all the code to do this can consume a large part of the time spent coding a project - and still, if a new errno value is added to the runtime system, the old code can not properly display a meaningful error message.

Good error handling code tends to clutter up what otherwise would be a neat and clean looking implementation.

Even worse, good error handling code is itself error prone, tends to be the least tested (and therefore buggy) part of the project, and is frequently simply omitted. The end result is likely a "blue screen of death" as the program failed to deal with some unanticipated error.

Quick and dirty programs are not worth writing tedious error handling code for, and so such utilities tend to be like using a table saw with no blade guards.

What's needed is an error handling philosophy and methodology such that:

  • It is standardized - consistent usage makes it more useful.
  • The result is reasonable even if the programmer fails to check for errors.
  • Old code can be reused with new code without having to modify the old code to be compatible with new error types.
  • No errors get inadvertently ignored.
  • 'Quick and dirty' utilities can be written that still correctly handle errors.
  • It is easy to make the error handling source code look good.

The D Error Handling Solution

Let's first make some observations and assumptions about errors:
  • Errors are not part of the normal flow of a program. Errors are exceptional, unusual, and unexpected.
  • Because errors are unusual, execution of error handling code is not performance critical.
  • The normal flow of program logic is performance critical.
  • All errors must be dealt with in some way, either by code explicitly written to handle them, or by some system default handling.
  • The code that detects an error knows more about the error than the code that must recover from the error.
The solution is to use exception handling to report errors. All errors are objects derived from abstract class Error. class Error has a pure virtual function called toString() which produces a char[] with a human readable description of the error.

If code detects an error like "out of memory," then an Error is thrown with a message saying "Out of memory". The function call stack is unwound, looking for a handler for the Error. Finally blocks are executed as the stack is unwound. If an error handler is found, execution resumes there. If not, the default Error handler is run, which displays the message and terminates the program.

How does this meet our criteria?

It is standardized - consistent usage makes it more useful.
This is the D way, and is used consistently in the D runtime library and examples.
The result is reasonable result even if the programmer fails to check for errors.
If no catch handlers are there for the errors, then the program gracefully exits through the default error handler with an appropriate message.
Old code can be reused with new code without having to modify the old code to be compatible with new error types.
Old code can decide to catch all errors, or only specific ones, propagating the rest upwards. In any case, there is no more need to correlate error numbers with messages, the correct message is always supplied.
No errors get inadvertently ignored.
Error exceptions get handled one way or another. There is nothing like a NULL pointer return indicating an error, followed by trying to use that NULL pointer.
'Quick and dirty' utilities can be written that still correctly handle errors.
Quick and dirty code need not write any error handling code at all, and don't need to check for errors. The errors will be caught, an appropriate message displayed, and the program gracefully shut down all by default.
It is easy to make the error handling source code look good.
The try/catch/finally statements look a lot nicer than endless if (error) goto errorhandler; statements.
How does this meet our assumptions about errors?
Errors are not part of the normal flow of a program. Errors are exceptional, unusual, and unexpected.
D exception handling fits right in with that.
Because errors are unusual, execution of error handling code is not performance critical.
Exception handling stack unwinding is a relatively slow process.
The normal flow of program logic is performance critical.
Since the normal flow code does not have to check every function call for error returns, it can be realistically faster to use exception handling for the errors.
All errors must be dealt with in some way, either by code explicitly written to handle them, or by some system default handling.
If there's no handler for a particular error, it is handled by the runtime library default handler. If an error is ignored, it is because the programmer specifically added code to ignore an error, which presumably means it was intentional.
The code that detects an error knows more about the error than the code that must recover from the error.
There is no more need to translate error codes into human readable strings, the correct string is generated by the error detection code, not the error recovery code. This also leads to consistent error messages for the same error between applications.
Using exceptions to handle errors leads to another issue - how to write exception safe programs. Here's how.


Unit Tests

Last update Sun Dec 30 20:34:44 2012

Unit Tests

UnitTest:
    unittest FunctionBody

Unit tests are a series of test cases applied to a module to determine if it is working properly. Ideally, unit tests should be run every time a program is compiled.

Unit tests are a special function defined like:

unittest {
  ...test code...
}

There can be any number of unit test functions in a module, including within struct, union and class declarations. They are executed in lexical order. Stylistically, a unit test for a function should appear immediately following it.

A compiler switch, such as -unittest for dmd, will cause the unittest test code to be compiled and incorporated into the resulting executable. The unittest code gets run after static initialization is run and before the main() function is called.

For example, given a class Sum that is used to add two values:

class Sum {
  int add(int x, int y) { return x + y; }

  unittest
  {
    Sum sum = new Sum;
    assert(sum.add(3,4) == 7);
    assert(sum.add(-2,0) == -2);
  }
}

Versioning

The version identifier unittest is predefined if the compilation is done with unit tests enabled.


Garbage Collection

Last update Sun Dec 30 20:34:42 2012

Garbage Collection

D is a fully garbage collected language. That means that it is never necessary to free memory. Just allocate as needed, and the garbage collector will periodically return all unused memory to the pool of available memory.

C and C++ programmers accustomed to explicitly managing memory allocation and deallocation will likely be skeptical of the benefits and efficacy of garbage collection. Experience both with new projects written with garbage collection in mind, and converting existing projects to garbage collection shows that:

  • Garbage collected programs are faster. This is counterintuitive, but the reasons are:
    • Reference counting is a common solution to solve explicit memory allocation problems. The code to implement the increment and decrement operations whenever assignments are made is one source of slowdown. Hiding it behind smart pointer classes doesn't help the speed. (Reference counting methods are not a general solution anyway, as circular references never get deleted.)
    • Destructors are used to deallocate resources acquired by an object. For most classes, this resource is allocated memory. With garbage collection, most destructors then become empty and can be discarded entirely.
    • All those destructors freeing memory can become significant when objects are allocated on the stack. For each one, some mechanism must be established so that if an exception happens, the destructors all get called in each frame to release any memory they hold. If the destructors become irrelevant, then there's no need to set up special stack frames to handle exceptions, and the code runs faster.
    • All the code necessary to manage memory can add up to quite a bit. The larger a program is, the less in the cache it is, the more paging it does, and the slower it runs.
    • Garbage collection kicks in only when memory gets tight. When memory is not tight, the program runs at full speed and does not spend any time freeing memory.
    • Modern garbage collectors are far more advanced now than the older, slower ones. Generational, copying collectors eliminate much of the inefficiency of early mark and sweep algorithms.
    • Modern garbage collectors do heap compaction. Heap compaction tends to reduce the number of pages actively referenced by a program, which means that memory accesses are more likely to be cache hits and less swapping.
    • Garbage collected programs do not suffer from gradual deterioration due to an accumulation of memory leaks.
  • Garbage collectors reclaim unused memory, therefore they do not suffer from "memory leaks" which can cause long running applications to gradually consume more and more memory until they bring down the system. GC programs have longer term stability.
  • Garbage collected programs have fewer hard-to-find pointer bugs. This is because there are no dangling references to freed memory. There is no code to explicitly manage memory, hence no bugs in such code.
  • Garbage collected programs are faster to develop and debug, because there's no need for developing, debugging, testing, or maintaining the explicit deallocation code.
  • Garbage collected programs can be significantly smaller, because there is no code to manage deallocation, and there is no need for exception handlers to deallocate memory.

Garbage collection is not a panacea. There are some downsides:

  • It is not predictable when a collection gets run, so the program can arbitrarily pause.
  • The time it takes for a collection to run is not bounded. While in practice it is very quick, this cannot be guaranteed.
  • All threads other than the collector thread must be halted while the collection is in progress.
  • Garbage collectors can keep around some memory that an explicit deallocator would not. In practice, this is not much of an issue since explicit deallocators usually have memory leaks causing them to eventually use far more memory, and because explicit deallocators do not normally return deallocated memory to the operating system anyway, instead just returning it to its own internal pool.
  • Garbage collection should be implemented as a basic operating system kernel service. But since they are not, garbage collecting programs must carry around with them the garbage collection implementation. While this can be a shared DLL, it is still there.

These constraints are addressed by techniques outlined in Memory Management.

How Garbage Collection Works

The GC works by:

  1. Looking for all the pointer ‘roots’ into GC allocated memory.
  2. Recursively scanning all allocated memory pointed to by roots looking for more pointers into GC allocated memory.
  3. Freeing all GC allocated memory that has no active pointers to it.
  4. Possibly compacting the remaining used memory by copying the allocated objects (called a copying collector).

Interfacing Garbage Collected Objects With Foreign Code

The garbage collector looks for roots in:

  1. its static data segment
  2. the stacks and register contents of each thread
  3. any roots added by std.gc.addRoot() or std.gc.addRange()

If the only root of an object is held outside of this, then the collecter will miss it and free the memory.

To avoid this from happening,

  • Maintain a root to the object in an area the collector does scan for roots.
  • Add a root to the object using std.gc.addRoot() or std.gc.addRange().
  • Reallocate and copy the object using the foreign code's storage allocator or using the C runtime library's malloc/free.

Pointers and the Garbage Collector

Pointers in D can be broadly divided into two categories: those that point to garbage collected memory, and those that do not. Examples of the latter are pointers created by calls to C's malloc(), pointers received from C library routines, pointers to static data, pointers to objects on the stack, etc. For those pointers, anything that is legal in C can be done with them.

For garbage collected pointers and references, however, there are some restrictions. These restrictions are minor, but they are intended to enable the maximum flexibility in garbage collector design.

Undefined behavior:

  • Do not xor pointers with other values, like the xor pointer linked list trick used in C.
  • Do not use the xor trick to swap two pointer values.
  • Do not store pointers into non-pointer variables using casts and other tricks.
    void* p;
...
int x = cast(int)p;   // error: undefined behavior
    The garbage collector does not scan non-pointer types for roots.
  • Do not take advantage of alignment of pointers to store bit flags in the low order bits:
    p = cast(void*)(cast(int)p | 1);  // error: undefined behavior
  • Do not store into pointers values that may point into the garbage collected heap:
    p = cast(void*)12345678;   // error: undefined behavior
    A copying garbage collector may change this value.
  • Do not store magic values into pointers, other than null.
  • Do not write pointer values out to disk and read them back in again.
  • Do not use pointer values to compute a hash function. A copying garbage collector can arbitrarily move objects around in memory, thus invalidating the computed hash value.
  • Do not depend on the ordering of pointers:
    if (p1 < p2)  // error: undefined behavior
  ...
    since, again, the garbage collector can move objects around in memory.
  • Do not add or subtract an offset to a pointer such that the result points outside of the bounds of the garbage collected object originally allocated.
    char* p = new char[10];
char* q = p + 6; // ok
q = p + 11;      // error: undefined behavior
q = p - 1;       // error: undefined behavior
  • Do not misalign pointers if those pointers may point into the gc heap, such as:
    align (1) struct Foo {
  byte b;
  char* p;  // misaligned pointer
}
    Misaligned pointers may be used if the underlying hardware supports them and the pointer is never used to point into the gc heap.
  • Do not use byte-by-byte memory copies to copy pointer values. This may result in intermediate conditions where there is not a valid pointer, and if the gc pauses the thread in such a condition, it can corrupt memory. Most implementations of memcpy() will work since the internal implementation of it does the copy in aligned chunks greater than or equal to a pointer size, but since this kind of implementation is not guaranteed by the C standard, use memcpy() only with extreme caution.
  • Do not have pointers in a struct instance that point back to the same instance. The trouble with this is if the instance gets moved in memory, the pointer will point back to where it came from, with likely disastrous results.

Things that are reliable and can be done:

  • Use a union to share storage with a pointer:
    union U { void* ptr; int value }
  • A pointer to the start of a garbage collected object need not be maintained if a pointer to the interior of the object exists.
    char[] p = new char[10];
char[] q = p[3..6];
// q is enough to hold on to the object, don't need to keep
// p as well.

One can avoid using pointers anyway for most tasks. D provides features rendering most explicit pointer uses obsolete, such as reference objects, dynamic arrays, and garbage collection. Pointers are provided in order to interface successfully with C APIs and for some low level work.

Working with the Garbage Collector

Garbage collection doesn't solve every memory deallocation problem. For example, if a root to a large data structure is kept, the garbage collector cannot reclaim it, even if it is never referred to again. To eliminate this problem, it is good practice to set a reference or pointer to an object to null when no longer needed.

This advice applies only to static references or references embedded inside other objects. There is not much point for such stored on the stack to be nulled, since the collector doesn't scan for roots past the top of the stack, and because new stack frames are initialized anyway.

Object Pinning and a Moving Garbage Collector

Although D does not currently use a moving garbage collector, by following the rules listed above one can be implemented. No special action is required to pin objects. A moving collector will only move objects for which there are no ambiguous references, and for which it can update those references. All other objects will be automatically pinned.

D Operations That Involve the Garbage Collector

Some sections of code may need to avoid using the garbage collector. The following constructs may allocate memory using the garbage collector:

  • NewExpression
  • Array appending
  • Array concatenation
  • Array literals (except when used to initialize static data)
  • Associative array literals
  • Any insertion, removal, or lookups in an associative array
  • Extracting keys or values from an associative array
  • An AssertExpression that fails its condition

References

  • Wikipedia
  • GC FAQ
  • Uniprocessor Garbage Collector Techniques
  • Garbage Collection : Algorithms for Automatic Dynamic Memory Management


Floating Point

Last update Sun Dec 30 20:34:42 2012

Floating Point

Floating Point Intermediate Values

On many computers, greater precision operations do not take any longer than lesser precision operations, so it makes numerical sense to use the greatest precision available for internal temporaries. The philosophy is not to dumb down the language to the lowest common hardware denominator, but to enable the exploitation of the best capabilities of target hardware.

For floating point operations and expression intermediate values, a greater precision can be used than the type of the expression. Only the minimum precision is set by the types of the operands, not the maximum. Implementation Note: On Intel x86 machines, for example, it is expected (but not required) that the intermediate calculations be done to the full 80 bits of precision implemented by the hardware.

It's possible that, due to greater use of temporaries and common subexpressions, optimized code may produce a more accurate answer than unoptimized code.

Algorithms should be written to work based on the minimum precision of the calculation. They should not degrade or fail if the actual precision is greater. Float or double types, as opposed to the real (extended) type, should only be used for:

  • reducing memory consumption for large arrays
  • when speed is more important than accuracy
  • data and function argument compatibility with C

Floating Point Constant Folding

Regardless of the type of the operands, floating point constant folding is done in real or greater precision. It is always done following IEEE 754 rules and round-to-nearest is used.

Floating point constants are internally represented in the implementation in at least real precision, regardless of the constant's type. The extra precision is available for constant folding. Committing to the precision of the result is done as late as possible in the compilation process. For example:

const float f = 0.2f;
writefln(f - 0.2);

will print 0. A non-const static variable's value cannot be propagated at compile time, so:

static float f = 0.2f;
writefln(f - 0.2);

will print 2.98023e-09. Hex floating point constants can also be used when specific floating point bit patterns are needed that are unaffected by rounding. To find the hex value of 0.2f:

import std.stdio;

void main()
{
    writefln("%a", 0.2f);
}

which is 0x1.99999ap-3. Using the hex constant:

const float f = 0x1.99999ap-3f;
writefln(f - 0.2);

prints 2.98023e-09.

Different compiler settings, optimization settings, and inlining settings can affect opportunities for constant folding, therefore the results of floating point calculations may differ depending on those settings.

Complex and Imaginary types

In existing languages, there is an astonishing amount of effort expended in trying to jam a complex type onto existing type definition facilities: templates, structs, operator overloading, etc., and it all usually ultimately fails. It fails because the semantics of complex operations can be subtle, and it fails because the compiler doesn't know what the programmer is trying to do, and so cannot optimize the semantic implementation.

This is all done to avoid adding a new type. Adding a new type means that the compiler can make all the semantics of complex work "right". The programmer then can rely on a correct (or at least fixable ) implementation of complex.

Coming with the baggage of a complex type is the need for an imaginary type. An imaginary type eliminates some subtle semantic issues, and improves performance by not having to perform extra operations on the implied 0 real part.

Imaginary literals have an i suffix:

ireal j = 1.3i;

There is no particular complex literal syntax, just add a real and imaginary type:

cdouble cd = 3.6 + 4i;
creal c = 4.5 + 2i;

Complex, real and imaginary numbers have two properties:

.re	get real part (0 for imaginary numbers)
.im	get imaginary part as a real (0 for real numbers)

For example:

cd.re		is 4.5 double
cd.im		is 2 double
c.re		is 4.5 real
c.im		is 2 real
j.im		is 1.3 real
j.re		is 0 real

Rounding Control

IEEE 754 floating point arithmetic includes the ability to set 4 different rounding modes. These are accessible via the functions in std.c.fenv.

Exception Flags

IEEE 754 floating point arithmetic can set several flags based on what happened with a computation:

FE_INVALID
FE_DENORMAL
FE_DIVBYZERO
FE_OVERFLOW
FE_UNDERFLOW
FE_INEXACT

These flags can be set/reset via the functions in std.c.fenv.

Floating Point Comparisons

In addition to the usual < <= > >= == != comparison operators, D adds more that are specific to floating point. These are !<>= <> <>= !<= !< !>= !> !<> and match the semantics for the NCEG extensions to C. See Floating point comparisons.

Floating Point Transformations

An implementation may perform transformations on floating point computations in order to reduce their strength, i.e. their runtime computation time. Because floating point math does not precisely follow mathematical rules, some transformations are not valid, even though some other programming languages still allow them.

The following transformations of floating point expressions are not allowed because under IEEE rules they could produce different results.

Disallowed Floating Point Transformations
transformation | comments
x + 0 → x | not valid if x is -0
x - 0 → x | not valid if x is ±0 and rounding is towards -∞
-x ↔ 0 - x | not valid if x is +0
x - x → 0 | not valid if x is NaN or ±∞
x - y ↔ -(y - x) | not valid because (1-1=+0) whereas -(1-1)=-0
x * 0 → 0 | not valid if x is NaN or ±∞
x / c ↔ x * (1/c) | valid if (1/c) yields an exact result
x != x → false | not valid if x is a NaN
x == x → true | not valid if x is a NaN
x !op y ↔ !(x op y) | not valid if x or y is a NaN

Of course, transformations that would alter side effects are also invalid.


Inline Assembler

Last update Sun Dec 30 20:34:42 2012

Inline Assembler

Some Assembly Required

D, being a systems programming language, provides an inline assembler. The inline assembler is standardized for D implementations across the same CPU family, for example, the Intel Pentium inline assembler for a Win32 D compiler will be syntax compatible with the inline assembler for Linux running on an Intel Pentium.

Implementations of D on different architectures, however, are free to innovate upon the memory model, function call/return conventions, argument passing conventions, etc.

This document describes the x86 implementation of the inline assembler.

AsmInstruction:
    Identifier : AsmInstruction
    align IntegerExpression
    even
    naked
    db Operands
    ds Operands
    di Operands
    dl Operands
    df Operands
    dd Operands
    de Operands
    Opcode
    Opcode Operands

Operands:
    Operand
    Operand , Operands

Labels

Assembler instructions can be labeled just like other statements. They can be the target of goto statements. For example:

void *pc;
asm
{
  call L1          ;
 L1:               ;
  pop  EBX         ;
  mov  pc[EBP],EBX ; // pc now points to code at L1
}

align IntegerExpression

IntegerExpression:
    IntegerLiteral
    Identifier

Causes the assembler to emit NOP instructions to align the next assembler instruction on an IntegerExpression boundary. IntegerExpression must evaluate at compile time to an integer that is a power of 2.

Aligning the start of a loop body can sometimes have a dramatic effect on the execution speed.

even

Causes the assembler to emit NOP instructions to align the next assembler instruction on an even boundary.

naked

Causes the compiler to not generate the function prolog and epilog sequences. This means such is the responsibility of inline assembly programmer, and is normally used when the entire function is to be written in assembler.

db, ds, di, dl, df, dd, de

These pseudo ops are for inserting raw data directly into the code. db is for bytes, ds is for 16 bit words, di is for 32 bit words, dl is for 64 bit words, df is for 32 bit floats, dd is for 64 bit doubles, and de is for 80 bit extended reals. Each can have multiple operands. If an operand is a string literal, it is as if there were length operands, where length is the number of characters in the string. One character is used per operand. For example:
asm
{
  db 5,6,0x83;   // insert bytes 0x05, 0x06, and 0x83 into code
  ds 0x1234;     // insert bytes 0x34, 0x12
  di 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00
  dl 0x1234;     // insert bytes 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  df 1.234;      // insert float 1.234
  dd 1.234;      // insert double 1.234
  de 1.234;      // insert real 1.234
  db "abc";      // insert bytes 0x61, 0x62, and 0x63
  ds "abc";      // insert bytes 0x61, 0x00, 0x62, 0x00, 0x63, 0x00
}

Opcodes

A list of supported opcodes is at the end.

The following registers are supported. Register names are always in upper case.

Register:
    AL AH AX EAX
    BL BH BX EBX
    CL CH CX ECX
    DL DH DX EDX
    BP EBP
    SP ESP
    DI EDI
    SI ESI
    ES CS SS DS GS FS
    CR0 CR2 CR3 CR4
    DR0 DR1 DR2 DR3 DR6 DR7
    TR3 TR4 TR5 TR6 TR7
    ST
    ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7)
    MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7
    XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7

Special Cases

lock, rep, repe, repne, repnz, repz
These prefix instructions do not appear in the same statement as the instructions they prefix; they appear in their own statement. For example:
asm {
  rep   ;
  movsb ;
}
pause
This opcode is not supported by the assembler, instead use
asm {
  rep  ;
  nop  ;
}
which produces the same result.
floating point ops
Use the two operand form of the instruction format;
fdiv ST(1);	// wrong
fmul ST;        // wrong
fdiv ST,ST(1);	// right
fmul ST,ST(0);	// right

Operands

Operand:
    AsmExp

AsmExp:
    AsmLogOrExp
    AsmLogOrExp ? AsmExp : AsmExp

AsmLogOrExp:
    AsmLogAndExp
    AsmLogAndExp || AsmLogAndExp

AsmLogAndExp:
    AsmOrExp
    AsmOrExp && AsmOrExp

AsmOrExp:
    AsmXorExp
    AsmXorExp | AsmXorExp

AsmXorExp:
    AsmAndExp
    AsmAndExp ^ AsmAndExp

AsmAndExp:
    AsmEqualExp
    AsmEqualExp & AsmEqualExp

AsmEqualExp:
    AsmRelExp
    AsmRelExp == AsmRelExp
    AsmRelExp != AsmRelExp

AsmRelExp:
    AsmShiftExp
    AsmShiftExp < AsmShiftExp
    AsmShiftExp <= AsmShiftExp
    AsmShiftExp > AsmShiftExp
    AsmShiftExp >= AsmShiftExp

AsmShiftExp:
    AsmAddExp
    AsmAddExp << AsmAddExp
    AsmAddExp >> AsmAddExp
    AsmAddExp >>> AsmAddExp

AsmAddExp:
    AsmMulExp
    AsmMulExp + AsmMulExp
    AsmMulExp - AsmMulExp

AsmMulExp:
    AsmBrExp
    AsmBrExp * AsmBrExp
    AsmBrExp / AsmBrExp
    AsmBrExp % AsmBrExp

AsmBrExp:
    AsmUnaExp
    AsmBrExp [ AsmExp ]

AsmUnaExp:
    AsmTypePrefix AsmExp
    offsetof AsmExp
    seg AsmExp
    + AsmUnaExp
    - AsmUnaExp
    ! AsmUnaExp
    ~ AsmUnaExp
    AsmPrimaryExp

AsmPrimaryExp:
    IntegerLiteral
    FloatLiteral
    __LOCAL_SIZE
    $
    Register
    DotIdentifier

DotIdentifier:
    Identifier
    Identifier . DotIdentifier

The operand syntax more or less follows the Intel CPU documentation conventions. In particular, the convention is that for two operand instructions the source is the right operand and the destination is the left operand. The syntax differs from that of Intel's in order to be compatible with the D language tokenizer and to simplify parsing.

The seg means load the segment number that the symbol is in. This is not relevant for flat model code. Instead, do a move from the relevant segment register.

Operand Types

AsmTypePrefix:
    near ptr
    far ptr
    byte ptr
    short ptr
    int ptr
    word ptr
    dword ptr
    qword ptr
    float ptr
    double ptr
    real ptr

In cases where the operand size is ambiguous, as in:

add	[EAX],3		;

it can be disambiguated by using an AsmTypePrefix:

add  byte ptr [EAX],3 ;
add  int ptr [EAX],7  ;

far ptr is not relevant for flat model code.

Struct/Union/Class Member Offsets

To access members of an aggregate, given a pointer to the aggregate is in a register, use the qualified name of the member:

struct Foo { int a,b,c; }
int bar(Foo *f) {
  asm {
    mov EBX,f          ;
    mov EAX,Foo.b[EBX] ;
  }
}

Stack Variables

Stack variables (variables local to a function and allocated on the stack) are accessed via the name of the variable indexed by EBP:

int foo(int x) {
  asm {
    mov EAX,x[EBP] ; // loads value of parameter x into EAX
    mov EAX,x      ; // does the same thing
  }
}

If the [EBP] is omitted, it is assumed for local variables. If naked is used, this no longer holds.

Special Symbols

$
Represents the program counter of the start of the next instruction. So,
jmp  $  ;
branches to the instruction following the jmp instruction. The $ can only appear as the target of a jmp or call instruction.
__LOCAL_SIZE
This gets replaced by the number of local bytes in the local stack frame. It is most handy when the naked is invoked and a custom stack frame is programmed.

Opcodes Supported

aaa | aad | aam | aas | adc
add | addpd | addps | addsd | addss
and | andnpd | andnps | andpd | andps
arpl | bound | bsf | bsr | bswap
bt | btc | btr | bts | call
cbw | cdq | clc | cld | clflush
cli | clts | cmc | cmova | cmovae
cmovb | cmovbe | cmovc | cmove | cmovg
cmovge | cmovl | cmovle | cmovna | cmovnae
cmovnb | cmovnbe | cmovnc | cmovne | cmovng
cmovnge | cmovnl | cmovnle | cmovno | cmovnp
cmovns | cmovnz | cmovo | cmovp | cmovpe
cmovpo | cmovs | cmovz | cmp | cmppd
cmpps | cmps | cmpsb | cmpsd | cmpss
cmpsw | cmpxch8b | cmpxchg | comisd | comiss
cpuid | cvtdq2pd | cvtdq2ps | cvtpd2dq | cvtpd2pi
cvtpd2ps | cvtpi2pd | cvtpi2ps | cvtps2dq | cvtps2pd
cvtps2pi | cvtsd2si | cvtsd2ss | cvtsi2sd | cvtsi2ss
cvtss2sd | cvtss2si | cvttpd2dq | cvttpd2pi | cvttps2dq
cvttps2pi | cvttsd2si | cvttss2si | cwd | cwde
da | daa | das | db | dd
de | dec | df | di | div
divpd | divps | divsd | divss | dl
dq | ds | dt | dw | emms
enter | f2xm1 | fabs | fadd | faddp
fbld | fbstp | fchs | fclex | fcmovb
fcmovbe | fcmove | fcmovnb | fcmovnbe | fcmovne
fcmovnu | fcmovu | fcom | fcomi | fcomip
fcomp | fcompp | fcos | fdecstp | fdisi
fdiv | fdivp | fdivr | fdivrp | feni
ffree | fiadd | ficom | ficomp | fidiv
fidivr | fild | fimul | fincstp | finit
fist | fistp | fisub | fisubr | fld
fld1 | fldcw | fldenv | fldl2e | fldl2t
fldlg2 | fldln2 | fldpi | fldz | fmul
fmulp | fnclex | fndisi | fneni | fninit
fnop | fnsave | fnstcw | fnstenv | fnstsw
fpatan | fprem | fprem1 | fptan | frndint
frstor | fsave | fscale | fsetpm | fsin
fsincos | fsqrt | fst | fstcw | fstenv
fstp | fstsw | fsub | fsubp | fsubr
fsubrp | ftst | fucom | fucomi | fucomip
fucomp | fucompp | fwait | fxam | fxch
fxrstor | fxsave | fxtract | fyl2x | fyl2xp1
hlt | idiv | imul | in | inc
ins | insb | insd | insw | int
into | invd | invlpg | iret | iretd
ja | jae | jb | jbe | jc
jcxz | je | jecxz | jg | jge
jl | jle | jmp | jna | jnae
jnb | jnbe | jnc | jne | jng
jnge | jnl | jnle | jno | jnp
jns | jnz | jo | jp | jpe
jpo | js | jz | lahf | lar
ldmxcsr | lds | lea | leave | les
lfence | lfs | lgdt | lgs | lidt
lldt | lmsw | lock | lods | lodsb
lodsd | lodsw | loop | loope | loopne
loopnz | loopz | lsl | lss | ltr
maskmovdqu | maskmovq | maxpd | maxps | maxsd
maxss | mfence | minpd | minps | minsd
minss | mov | movapd | movaps | movd
movdq2q | movdqa | movdqu | movhlps | movhpd
movhps | movlhps | movlpd | movlps | movmskpd
movmskps | movntdq | movnti | movntpd | movntps
movntq | movq | movq2dq | movs | movsb
movsd | movss | movsw | movsx | movupd
movups | movzx | mul | mulpd | mulps
mulsd | mulss | neg | nop | not
or | orpd | orps | out | outs
outsb | outsd | outsw | packssdw | packsswb
packuswb | paddb | paddd | paddq | paddsb
paddsw | paddusb | paddusw | paddw | pand
pandn | pavgb | pavgw | pcmpeqb | pcmpeqd
pcmpeqw | pcmpgtb | pcmpgtd | pcmpgtw | pextrw
pinsrw | pmaddwd | pmaxsw | pmaxub | pminsw
pminub | pmovmskb | pmulhuw | pmulhw | pmullw
pmuludq | pop | popa | popad | popf
popfd | por | prefetchnta | prefetcht0 | prefetcht1
prefetcht2 | psadbw | pshufd | pshufhw | pshuflw
pshufw | pslld | pslldq | psllq | psllw
psrad | psraw | psrld | psrldq | psrlq
psrlw | psubb | psubd | psubq | psubsb
psubsw | psubusb | psubusw | psubw | punpckhbw
punpckhdq | punpckhqdq | punpckhwd | punpcklbw | punpckldq
punpcklqdq | punpcklwd | push | pusha | pushad
pushf | pushfd | pxor | rcl | rcpps
rcpss | rcr | rdmsr | rdpmc | rdtsc
rep | repe | repne | repnz | repz
ret | retf | rol | ror | rsm
rsqrtps | rsqrtss | sahf | sal | sar
sbb | scas | scasb | scasd | scasw
seta | setae | setb | setbe | setc
sete | setg | setge | setl | setle
setna | setnae | setnb | setnbe | setnc
setne | setng | setnge | setnl | setnle
setno | setnp | setns | setnz | seto
setp | setpe | setpo | sets | setz
sfence | sgdt | shl | shld | shr
shrd | shufpd | shufps | sidt | sldt
smsw | sqrtpd | sqrtps | sqrtsd | sqrtss
stc | std | sti | stmxcsr | stos
stosb | stosd | stosw | str | sub
subpd | subps | subsd | subss | sysenter
sysexit | test | ucomisd | ucomiss | ud2
unpckhpd | unpckhps | unpcklpd | unpcklps | verr
verw | wait | wbinvd | wrmsr | xadd
xchg | xlat | xlatb | xor | xorpd
xorps |  |  |  |

Pentium 4 (Prescott) Opcodes Supported

addsubpd | addsubps | fisttp | haddpd | haddps
hsubpd | hsubps | lddqu | monitor | movddup
movshdup | movsldup | mwait |  |

AMD Opcodes Supported

pavgusb | pf2id | pfacc | pfadd | pfcmpeq
pfcmpge | pfcmpgt | pfmax | pfmin | pfmul
pfnacc | pfpnacc | pfrcp | pfrcpit1 | pfrcpit2
pfrsqit1 | pfrsqrt | pfsub | pfsubr | pi2fd
pmulhrw | pswapd


Documentation Generator

Last update Sun Dec 30 20:34:43 2012

Embedded Documentation

The D programming language enables embedding both contracts and test code along side the actual code, which helps to keep them all consistent with each other. One thing lacking is the documentation, as ordinary comments are usually unsuitable for automated extraction and formatting into manual pages. Embedding the user documentation into the source code has important advantages, such as not having to write the documentation twice, and the likelihood of the documentation staying consistent with the code.

Some existing approaches to this are:

  • Doxygen which already has some support for D
  • Java's Javadoc, probably the most well-known
  • C#'s embedded XML
  • Other documentation tools

D's goals for embedded documentation are:

  1. It looks good as embedded documentation, not just after it is extracted and processed.
  2. It's easy and natural to write, i.e. minimal reliance on <tags> and other clumsy forms one would never see in a finished document.
  3. It does not repeat information that the compiler already knows from parsing the code.
  4. It doesn't rely on embedded HTML, as such will impede extraction and formatting for other purposes.
  5. It's based on existing D comment forms, so it is completely independent of parsers only interested in D code.
  6. It should look and feel different from code, so it won't be visually confused with code.
  7. It should be possible for the user to use Doxygen or other documentation extractor if desired.

Specification

The specification for the form of embedded documentation comments only specifies how information is to be presented to the compiler. It is implementation-defined how that information is used and the form of the final presentation. Whether the final presentation form is an HTML web page, a man page, a PDF file, etc. is not specified as part of the D Programming Language.

Phases of Processing

Embedded documentation comments are processed in a series of phases:

  1. Lexical - documentation comments are identified and attached to tokens.
  2. Parsing - documentation comments are associated with specific declarations and combined.
  3. Sections - each documentation comment is divided up into a sequence of sections.
  4. Special sections are processed.
  5. Highlighting of non-special sections is done.
  6. All sections for the module are combined.
  7. Macro text substitution is performed to produce the final result.

Lexical

Embedded documentation comments are one of the following forms:

  1. /** ... */ The two *'s after the opening /
  2. /++ ... +/ The two +'s after the opening /
  3. /// The three slashes

The following are all embedded documentation comments:

/// This is a one line documentation comment.

/** So is this. */

/++ And this. +/

/**
   This is a brief documentation comment.
 */

/**
 * The leading * on this line is not part of the documentation comment.
 */

/*********************************
   The extra *'s immediately following the /** are not
   part of the documentation comment.
 */

/++
   This is a brief documentation comment.
 +/

/++
 + The leading + on this line is not part of the documentation comment.
 +/

/+++++++++++++++++++++++++++++++++
   The extra +'s immediately following the / ++ are not
   part of the documentation comment.
 +/

/**************** Closing *'s are not part *****************/

The extra *'s and +'s on the comment opening, closing and left margin are ignored and are not part of the embedded documentation. Comments not following one of those forms are not documentation comments.

Parsing

Each documentation comment is associated with a declaration. If the documentation comment is on a line by itself or with only whitespace to the left, it refers to the next declaration. Multiple documentation comments applying to the same declaration are concatenated. Documentation comments not associated with a declaration are ignored. Documentation comments preceding the ModuleDeclaration apply to the entire module. If the documentation comment appears on the same line to the right of a declaration, it applies to that.

If a documentation comment for a declaration consists only of the identifier ditto then the documentation comment for the previous declaration at the same declaration scope is applied to this declaration as well.

If there is no documentation comment for a declaration, that declaration may not appear in the output. To ensure it does appear in the output, put an empty declaration comment for it.

int a;  /// documentation for a; b has no documentation
int b;

/** documentation for c and d */
/** more documentation for c and d */
int c;
/** ditto */
int d;

/** documentation for e and f */ int e;
int f;	/// ditto

/** documentation for g */
int g; /// more documentation for g

/// documentation for C and D
class C {
  int x; /// documentation for C.x

  /** documentation for C.y and C.z */
  int y;
  int z; /// ditto
}

/// ditto
class D { }

Sections

The document comment is a series of Sections. A Section is a name that is the first non-blank character on a line immediately followed by a ':'. This name forms the section name. The section name is not case sensitive.

Summary

The first section is the Summary, and does not have a section name. It is first paragraph, up to a blank line or a section name. While the summary can be any length, try to keep it to one line. The Summary section is optional.

Description

The next unnamed section is the Description. It consists of all the paragraphs following the Summary until a section name is encountered or the end of the comment.

While the Description section is optional, there cannot be a Description without a Summary section.

/***********************************
 * Brief summary of what
 * myfunc does, forming the summary section.
 *
 * First paragraph of synopsis description.
 *
 * Second paragraph of
 * synopsis description.
 */

void myfunc() { }

Named sections follow the Summary and Description unnamed sections.

Standard Sections

For consistency and predictability, there are several standard sections. None of these are required to be present.

Authors:
Lists the author(s) of the declaration.
/**
 * Authors: Melvin D. Nerd, melvin@mailinator.com
 */
Bugs:
Lists any known bugs.
/**
 * Bugs: Doesn't work for negative values.
 */
Date:
Specifies the date of the current revision. The date should be in a form parseable by std.date.
/**
 * Date: March 14, 2003
 */
Deprecated:
Provides an explanation for and corrective action to take if the associated declaration is marked as deprecated.
/**
 * Deprecated: superseded by function bar().
 */

deprecated void foo() { ... }
Examples:
Any usage examples
/**
 * Examples:
 * --------------------
 * writefln("3"); // writes '3' to stdout
 * --------------------
 */
History:
Revision history.
/**
 * History:
 *	V1 is initial version
 *
 *	V2 added feature X
 */
License:
Any license information for copyrighted code.
/**
 * License: use freely for any purpose
 */

void bar() { ... }
Returns:
Explains the return value of the function. If the function returns void, don't redundantly document it.
/**
 * Read the file.
 * Returns: The contents of the file.
 */

void[] readFile(char[] filename) { ... }
See_Also:
List of other symbols and URL's to related items.
/**
 * See_Also:
 *    foo, bar, http://www.digitalmars.com/d/phobos/index.html
 */
Standards:
If this declaration is compliant with any particular standard, the description of it goes here.
/**
 * Standards: Conforms to DSPEC-1234
 */
Throws:
Lists exceptions thrown and under what circumstances they are thrown.
/**
 * Write the file.
 * Throws: WriteException on failure.
 */

void writeFile(char[] filename) { ... }
Version:
Specifies the current version of the declaration.
/**
 * Version: 1.6a
 */

Special Sections

Some sections have specialized meanings and syntax.

Copyright:
This contains the copyright notice. The macro COPYRIGHT is set to the contents of the section when it documents the module declaration. The copyright section only gets this special treatment when it is for the module declaration.
/** Copyright: Public Domain */

module foo;
Params:
Function parameters can be documented by listing them in a params section. Each line that starts with an identifier followed by an '=' starts a new parameter description. A description can span multiple lines.
/***********************************
 * foo does this.
 * Params:
 *	x =	is for this
 *		and not for that
 *	y =	is for that
 */

void foo(int x, int y)
{
}
Macros:
The macros section follows the same syntax as the Params: section. It's a series of NAME=value pairs. The NAME is the macro name, and value is the replacement text.
/**
 * Macros:
 *	FOO =	now is the time for
 *		all good men
 *	BAR =	bar
 *	MAGENTA =   &lt;font color=magenta&gt;&lt;/font&gt;
 */

Highlighting

Embedded Comments

The documentation comments can themselves be commented using the $(DDOC_COMMENT comment text) syntax. These comments do not nest.

Embedded Code

D code can be embedded using lines beginning with at least three hyphens (ignoring whitespace) to delineate the code section:

/++
 + Our function.
 +
 + Example:
 + ---
 + import std.stdio;
 +
 + void foo()
 + {
 +     writefln("foo!");  /* print the string */
 + }
 + ---
 +/

Note that the documentation comment uses the /++ ... +/ form so that /* ... */ can be used inside the code section.

Embedded HTML

HTML can be embedded into the documentation comments, and it will be passed through to the HTML output unchanged. However, since it is not necessarily true that HTML will be the desired output format of the embedded documentation comment extractor, it is best to avoid using it where practical.

/**
 * Example of embedded HTML:
 *
 * <ol>
 *   <li><a href="http://www.digitalmars.com">Digital Mars</a></li>
 *   <li><a href="http://www.classicempire.com">Empire</a></li>
 * </ol>
 */

Emphasis

Identifiers in documentation comments that are function parameters or are names that are in scope at the associated declaration are emphasized in the output. This emphasis can take the form of italics, boldface, a hyperlink, etc. How it is emphasized depends on what it is - a function parameter, type, D keyword, etc. To prevent unintended emphasis of an identifier, it can be preceded by an underscore (_). The underscore will be stripped from the output.

Character Entities

Some characters have special meaning to the documentation processor, to avoid confusion it can be best to replace them with their corresponding character entities:

Characters and Entities
Character | Entity
< | &lt;
> | &gt;
& | &amp;

It is not necessary to do this inside a code section, or if the special character is not immediately followed by a # or a letter.

No Documentation

No documentation is generated for the following constructs, even if they have a documentation comment:

  • Invariants
  • Destructors
  • Static constructors and static destructors
  • Class info, type info, and module info

Macros

The documentation comment processor includes a simple macro text preprocessor. When a $(NAME) appears in section text it is replaced with NAME's corresponding replacement text. The replacement text is then recursively scanned for more macros. If a macro is recursively encountered, with no argument or with the same argument text as the enclosing macro, it is replaced with no text. Macro invocations that cut across replacement text boundaries are not expanded. If the macro name is undefined, the replacement text has no characters in it. If a $(NAME) is desired to exist in the output without being macro expanded, the $ should be replaced with &#36;.

Macros can have arguments. Any text from the end of the identifier to the closing ‘)’ is the $0 argument. A $0 in the replacement text is replaced with the argument text. If there are commas in the argument text, $1 will represent the argument text up to the first comma, $2 from the first comma to the second comma, etc., up to $9. $+ represents the text from the first comma to the closing ‘)’. The argument text can contain nested parentheses, "" or '' strings, comments, or tags. If stray, unnested parentheses are used, they can be replaced with the entity &#40; for ( and &#41; for ).

Macro definitions come from the following sources, in the specified order:

  1. Predefined macros.
  2. Definitions from file specified by sc.ini's or dmd.conf DDOCFILE setting.
  3. Definitions from *.ddoc files specified on the command line.
  4. Runtime definitions generated by Ddoc.
  5. Definitions from any Macros: sections.

Macro redefinitions replace previous definitions of the same name. This means that the sequence of macro definitions from the various sources forms a hierarchy.

Macro names beginning with "D_" and "DDOC_" are reserved.

Predefined Macros

These are hardwired into Ddoc, and represent the minimal definitions needed by Ddoc to format and highlight the presentation. The definitions are for simple HTML.

B =     <b>$0</b>
I =     <i>$0</i>
U =     <u>$0</u>
P =     <p>$0</p>
DL =    <dl>$0</dl>
DT =    <dt>$0</dt>
DD =    <dd>$0</dd>
TABLE = <table>$0</table>
TR =    <tr>$0</tr>
TH =    <th>$0</th>
TD =    <td>$0</td>
OL =    <ol>$0</ol>
UL =    <ul>$0</ul>
LI =    <li>$0</li>
BIG =   <big>$0</big>
SMALL = <small>$0</small>
BR =    <br>
LINK =  <a href="$0">$0</a>
LINK2 = <a href="$1">$+</a>
LPAREN= (
RPAREN= )

RED =   <font color=red>$0</font>
BLUE =  <font color=blue>$0</font>
GREEN = <font color=green>$0</font>
YELLOW =<font color=yellow>$0</font>
BLACK = <font color=black>$0</font>
WHITE = <font color=white>$0</font>

D_CODE = <pre class="d_code">$0</pre>
D_COMMENT = $(GREEN $0)
D_STRING  = $(RED $0)
D_KEYWORD = $(BLUE $0)
D_PSYMBOL = $(U $0)
D_PARAM   = $(I $0)

DDOC = <html><head>
       <META http-equiv="content-type" content="text/html; charset=utf-8">
       <title>$(TITLE)</title>
       </head><body>
       <h1>$(TITLE)</h1>
       $(BODY)
       </body></html>

DDOC_COMMENT   = <!-- $0 -->
DDOC_DECL      = $(DT $(BIG $0))
DDOC_DECL_DD   = $(DD $0)
DDOC_DITTO     = $(BR)$0
DDOC_SECTIONS  = $0
DDOC_SUMMARY   = $0$(BR)$(BR)
DDOC_DESCRIPTION = $0$(BR)$(BR)
DDOC_AUTHORS   = $(B Authors:)$(BR)
        $0$(BR)$(BR)
DDOC_BUGS      = $(RED BUGS:)$(BR)
        $0$(BR)$(BR)
DDOC_COPYRIGHT = $(B Copyright:)$(BR)
        $0$(BR)$(BR)
DDOC_DATE      = $(B Date:)$(BR)
        $0$(BR)$(BR)
DDOC_DEPRECATED = $(RED Deprecated:)$(BR)
        $0$(BR)$(BR)
DDOC_EXAMPLES  = $(B Examples:)$(BR)
        $0$(BR)$(BR)
DDOC_HISTORY   = $(B History:)$(BR)
        $0$(BR)$(BR)
DDOC_LICENSE   = $(B License:)$(BR)
        $0$(BR)$(BR)
DDOC_RETURNS   = $(B Returns:)$(BR)
        $0$(BR)$(BR)
DDOC_SEE_ALSO  = $(B See Also:)$(BR)
        $0$(BR)$(BR)
DDOC_STANDARDS = $(B Standards:)$(BR)
        $0$(BR)$(BR)
DDOC_THROWS    = $(B Throws:)$(BR)
        $0$(BR)$(BR)
DDOC_VERSION   = $(B Version:)$(BR)
        $0$(BR)$(BR)
DDOC_SECTION_H = $(B $0)$(BR)$(BR)
DDOC_SECTION   = $0$(BR)$(BR)
DDOC_MEMBERS   = $(DL $0)
DDOC_MODULE_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_CLASS_MEMBERS    = $(DDOC_MEMBERS $0)
DDOC_STRUCT_MEMBERS   = $(DDOC_MEMBERS $0)
DDOC_ENUM_MEMBERS     = $(DDOC_MEMBERS $0)
DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)
DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)
DDOC_PARAM_ROW = $(TR $0)
DDOC_PARAM_ID  = $(TD $0)
DDOC_PARAM_DESC  = $(TD $0)
DDOC_BLANKLINE = $(BR)$(BR)

DDOC_PSYMBOL = $(U $0)
DDOC_KEYWORD = $(B $0)
DDOC_PARAM   = $(I $0)

Ddoc does not generate HTML code. It formats into the basic formatting macros, which (in their predefined form) are then expanded into HTML. If output other than HTML is desired, then these macros need to be redefined.

Basic Formatting Macros
B | boldface the argument
I | italicize the argument
U | underline the argument
P | argument is a paragraph
DL | argument is a definition list
DT | argument is a definition in a definition list
DD | argument is a description of a definition
TABLE | argument is a table
TR | argument is a row in a table
TH | argument is a header entry in a row
TD | argument is a data entry in a row
OL | argument is an ordered list
UL | argument is an unordered list
LI | argument is an item in a list
BIG | argument is one font size bigger
SMALL | argument is one font size smaller
BR | start new line
LINK | generate clickable link on argument
LINK2 | generate clickable link, first arg is address
RED | argument is set to be red
BLUE | argument is set to be blue
GREEN | argument is set to be green
YELLOW | argument is set to be yellow
BLACK | argument is set to be black
WHITE | argument is set to be white
D_CODE | argument is D code
DDOC | overall template for output

DDOC is special in that it specifies the boilerplate into which the entire generated text is inserted (represented by the Ddoc generated macro BODY). For example, in order to use a style sheet, DDOC would be redefined as:

DDOC =	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html><head>
    <META http-equiv="content-type" content="text/html; charset=utf-8">
    <title>$(TITLE)</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    </head><body>
    <h1>$(TITLE)</h1>
    $(BODY)
    </body></html>

DDOC_COMMENT is used to insert comments into the output file.

Highlighting of D code is performed by the following macros:

D Code Formatting Macros
D_COMMENT | Highlighting of comments
D_STRING | Highlighting of string literals
D_KEYWORD | Highlighting of D keywords
D_PSYMBOL | Highlighting of current declaration name
D_PARAM | Highlighting of current function declaration parameters

The highlighting macros start with DDOC_. They control the formatting of individual parts of the presentation.

Ddoc Section Formatting Macros
DDOC_DECL | Highlighting of the declaration.
DDOC_DECL_DD | Highlighting of the description of a declaration.
DDOC_DITTO | Highlighting of ditto declarations.
DDOC_SECTIONS | Highlighting of all the sections.
DDOC_SUMMARY | Highlighting of the summary section.
DDOC_DESCRIPTION | Highlighting of the description section.
DDOC_AUTHORS .. DDOC_VERSION | Highlighting of the corresponding standard section.
DDOC_SECTION_H | Highlighting of the section name of a non-standard section.
DDOC_SECTION | Highlighting of the contents of a non-standard section.
DDOC_MEMBERS | Default highlighting of all the members of a class, struct, etc.
DDOC_MODULE_MEMBERS | Highlighting of all the members of a module.
DDOC_CLASS_MEMBERS | Highlighting of all the members of a class.
DDOC_STRUCT_MEMBERS | Highlighting of all the members of a struct.
DDOC_ENUM_MEMBERS | Highlighting of all the members of an enum.
DDOC_TEMPLATE_MEMBERS | Highlighting of all the members of a template.
DDOC_PARAMS | Highlighting of a function parameter section.
DDOC_PARAM_ROW | Highlighting of a name=value function parameter.
DDOC_PARAM_ID | Highlighting of the parameter name.
DDOC_PARAM_DESC | Highlighting of the parameter value.
DDOC_PSYMBOL | Highlighting of declaration name to which a particular section is referring.
DDOC_KEYWORD | Highlighting of D keywords.
DDOC_PARAM | Highlighting of function parameters.
DDOC_BLANKLINE | Inserts a blank line.

For example, one could redefine DDOC_SUMMARY:

DDOC_SUMMARY = $(GREEN $0)

And all the summary sections will now be green.

Macro Definitions from sc.ini's DDOCFILE

A text file of macro definitions can be created, and specified in sc.ini:

DDOCFILE=myproject.ddoc

Macro Definitions from .ddoc Files on the Command Line

File names on the DMD command line with the extension .ddoc are text files that are read and processed in order.

Macro Definitions Generated by Ddoc

Generated Macro Definitions
Macro Name | Contents
BODY | Set to the generated document text.
TITLE | Set to the module name.
DATETIME | Set to the current date and time.
YEAR | Set to the current year.
COPYRIGHT | Set to the contents of any Copyright: section that is part of the module comment.
DOCFILENAME | Set to the name of the generated output file.

Using Ddoc for other Documentation

Ddoc is primarily designed for use in producing documentation from embedded comments. It can also, however, be used for processing other general documentation. The reason for doing this would be to take advantage of the macro capability of Ddoc and the D code syntax highlighting capability.

If the .d source file starts with the string "Ddoc" then it is treated as general purpose documentation, not as a D code source file. From immediately after the "Ddoc" string to the end of the file or any "Macros:" section forms the document. No automatic highlighting is done to that text, other than highlighting of D code embedded between lines delineated with --- lines. Only macro processing is done.

Much of the D documentation itself is generated this way, including this page. Such documentation is marked at the bottom as being generated by Ddoc.

References

CandyDoc is a very nice example of how one can customize the Ddoc results with macros and style sheets.


Interfacing to C

Last update Sun Dec 30 20:34:43 2012

Interfacing to C

D is designed to fit comfortably with a C compiler for the target system. D makes up for not having its own VM by relying on the target environment's C runtime library. It would be senseless to attempt to port to D or write D wrappers for the vast array of C APIs available. How much easier it is to just call them directly.

This is done by matching the C compiler's data types, layouts, and function call/return sequences.

Calling C Functions

C functions can be called directly from D. There is no need for wrapper functions, argument swizzling, and the C functions do not need to be put into a separate DLL.

The C function must be declared and given a calling convention, most likely the "C" calling convention, for example:

extern (C) int strcmp(char* string1, char* string2);

and then it can be called within D code in the obvious way:

import std.string;
int myDfunction(char[] s) {
  return strcmp(std.string.toStringz(s), "foo");
}

There are several things going on here:

  • D understands how C function names are "mangled" and the correct C function call/return sequence.
  • C functions cannot be overloaded with another C function with the same name.
  • There are no __cdecl, __far, __stdcall, __declspec, or other such C extended type modifiers in D. These are handled by linkage attributes, such as extern (C).
  • There are no const or volatile type modifiers in D. To declare a C function that uses those type modifiers, just drop those keywords from the declaration.
  • Strings are not 0 terminated in D. See "Data Type Compatibility" for more information about this. However, string literals in D are 0 terminated.

C code can correspondingly call D functions, if the D functions use an attribute that is compatible with the C compiler, most likely the extern (C):

// myfunc() can be called from any C function
extern (C) {
  void myfunc(int a, int b) {
    ...
  }
}

Storage Allocation

C code explicitly manages memory with calls to malloc() and free(). D allocates memory using the D garbage collector, so no explicit free's are necessary.

D can still explicitly allocate memory using std.c.stdlib.malloc() and std.c.stdlib.free(), these are useful for connecting to C functions that expect malloc'd buffers, etc.

If pointers to D garbage collector allocated memory are passed to C functions, it's critical to ensure that that memory will not be collected by the garbage collector before the C function is done with it. This is accomplished by:

  • Making a copy of the data using std.c.stdlib.malloc() and passing the copy instead.
  • Leaving a pointer to it on the stack (as a parameter or automatic variable), as the garbage collector will scan the stack.
  • Leaving a pointer to it in the static data segment, as the garbage collector will scan the static data segment.
  • Registering the pointer with the garbage collector with the std.gc.addRoot() or std.gc.addRange() calls.

An interior pointer to the allocated memory block is sufficient to let the GC know the object is in use; i.e. it is not necessary to maintain a pointer to the beginning of the allocated memory.

The garbage collector does not scan the stacks of threads not created by the D Thread interface. Nor does it scan the data segments of other DLL's, etc.

Data Type Compatibility

D And C Type Equivalence
D | C
 | 32 bit | 64 bit
void | void
byte | signed char
ubyte | unsigned char
char | char (chars are unsigned in D)
wchar | wchar_t (when sizeof(wchar_t) is 2)
dchar | wchar_t (when sizeof(wchar_t) is 4)
short | short
ushort | unsigned short
int | int
uint | unsigned
long | long long | long
ulong | unsigned long long | unsigned long
float | float
double | double
real | long double
ifloat | float _Imaginary
idouble | double _Imaginary
ireal | long double _Imaginary
cfloat | float _Complex
cdouble | double _Complex
creal | long double _Complex
struct | struct
union | union
enum | enum
class | no equivalent
type* | type *
type[dim] | type[dim]
type[dim]* | type(*)[dim]
type[] | no equivalent
type[type] | no equivalent
type function(parameters) | type(*)(parameters)
type delegate(parameters) | no equivalent
size_t | size_t
ptrdiff_t | ptrdiff_t

These equivalents hold for most C compilers. The C standard does not pin down the sizes of the types, so some care is needed.

Calling printf()

This mostly means checking that the printf format specifier matches the corresponding D data type. Although printf is designed to handle 0 terminated strings, not D dynamic arrays of chars, it turns out that since D dynamic arrays are a length followed by a pointer to the data, the %.*s format works:

void foo(char[] string) {
  printf("my string is: %.*s\n", string.length, string.ptr);
}

The printf format string literal in the example doesn't end with '\0'. This is because string literals, when they are not part of an initializer to a larger data structure, have a '\0' character helpfully stored after the end of them.

An improved D function for formatted output is std.stdio.writef().

Structs and Unions

D structs and unions are analogous to C's.

C code often adjusts the alignment and packing of struct members with a command line switch or with various implementation specific #pragma's. D supports explicit alignment attributes that correspond to the C compiler's rules. Check what alignment the C code is using, and explicitly set it for the D struct declaration.

D does not support bit fields. If needed, they can be emulated with shift and mask operations, or use the std.bitmanip.bitfields library type. htod will convert bit fields to inline functions that do the right shift and masks.

Using Existing C Libraries

Since D can call C code directly, it can also call any C library functions, giving D access to the smorgasbord of existing C libraries. To do so, however, one needs to write a D interface (.di) file, which is a translation of the C .h header file for the C library into D.

For popular C libraries, the first place to look for the corresponding D interface file is the Deimos Project. If it isn't there already, and you write one, please contribute it to the Deimos Project.

Accessing C Globals

C globals can be accessed directly from D. C globals have the C naming convention, and so must be in an extern (C) block. Use the extern storage class to indicate that the global is allocated in the C code, not the D code.

extern (C) extern __gshared int x;

Interfacing to C++

D does not provide an interface to C++, other than through COM programming. Since D, however, interfaces directly to C, it can interface directly to C++ code if it is declared as having C linkage.

D class objects are incompatible with C++ class objects.


Portability

Last update Sun Dec 30 20:34:43 2012

Portability Guide

It's good software engineering practice to minimize gratuitous portability problems in the code. Techniques to minimize potential portability problems are:

  • The integral and floating type sizes should be considered as minimums. Algorithms should be designed to continue to work properly if the type size increases.
  • Floating point computations can be carried out at a higher precision than the size of the floating point variable can hold. Floating point algorithms should continue to work properly if precision is arbitrarily increased.
  • Avoid depending on the order of side effects in a computation that may get reordered by the compiler. For example:
    a + b + c

    can be evaluated as (a + b) + c, a + (b + c), (a + c) + b, (c + b) + a, etc. Parentheses control operator precedence, parentheses do not control order of evaluation.

    Function parameters can be evaluated either left to right or right to left, depending on the particular calling conventions used.

    If the operands of an associative operator + or * are floating point values, the expression is not reordered.

  • Avoid dependence on byte order; i.e. whether the CPU is big-endian or little-endian.
  • Avoid dependence on the size of a pointer or reference being the same size as a particular integral type.
  • If size dependencies are inevitable, put an assert in the code to verify it:
    assert(int.sizeof == (int*).sizeof);

32 to 64 Bit Portability

64 bit processors and operating systems are here. With that in mind:

  • Integral types will remain the same sizes between 32 and 64 bit code.
  • Pointers and object references will increase in size from 4 bytes to 8 bytes going from 32 to 64 bit code.
  • Use size_t as an alias for an unsigned integral type that can span the address space. Array indices should be of type size_t.
  • Use ptrdiff_t as an alias for a signed integral type that can span the address space. A type representing the difference between two pointers should be of type ptrdiff_t.
  • The .length, .size, .sizeof, .offsetof and .alignof properties will be of type size_t.

Endianness

Endianness refers to the order in which multibyte types are stored. The two main orders are big endian and little endian. The compiler predefines the version identifier BigEndian or LittleEndian depending on the order of the target system. The x86 systems are all little endian.

The times when endianness matters are:

  • When reading data from an external source (like a file) written in a different endian format.
  • When reading or writing individual bytes of a multibyte type like longs or doubles.

OS Specific Code

System specific code is handled by isolating the differences into separate modules. At compile time, the correct system specific module is imported.

Minor differences can be handled by constant defined in a system specific import, and then using that constant in an IfStatement or StaticIfStatement.


Embedding D in HTML

Last update Sun Dec 30 20:34:43 2012

Embedding D in HTML

The D compiler is designed to be able to extract and compile D code embedded within HTML files. This capability means that D code can be written to be displayed within a browser utilizing the full formatting and display capability of HTML.

For example, it is possible to make all uses of a class name actually be hyperlinks to where the class is defined. There's nothing new to learn for the person browsing the code, he just uses the normal features of an HTML browser. Strings can be displayed in green, comments in red, and keywords in boldface, for one possibility. It is even possible to embed pictures in the code, as normal HTML image tags.

Embedding D in HTML makes it possible to put the documentation for code and the code itself all together in one file. It is no longer necessary to relegate documentation in comments, to be extracted later by a tech writer. The code and the documentation for it can be maintained simultaneously, with no duplication of effort.

How it works is straightforward. If the source file to the compiler ends in .htm or .html, the code is assumed to be embedded in HTML. The source is then preprocessed by stripping all text outside of <code> and </code> tags. Then, all other HTML tags are stripped, and embedded character encodings are converted to ASCII. The processing does not attempt to diagnose errors in the HTML itself. All newlines in the original HTML remain in their corresponding positions in the preprocessed text, so the debug line numbers remain consistent. The resulting text is then fed to the D compiler.

Here's an example of the D program "hello world" embedded in this very HTML file. This file can be compiled and run.

import std.stdio;

int main()
{
 writefln("hello world");
 return 0;
}


Named Character Entities

Last update Sun Dec 30 20:34:43 2012

Named Character Entities

These are the character entity names supported by D.

Note: Not all will display properly in the Symbol column in all browsers.

Named Character Entities
Name | Value | Symbol
quot | 34 | "
amp | 38 | &
lt | 60 | <
gt | 62 | >
OElig | 338 | Œ
oelig | 339 | œ
Scaron | 352 | Š
scaron | 353 | š
Yuml | 376 | Ÿ
circ | 710 | ˆ
tilde | 732 | ˜
ensp | 8194 |
emsp | 8195 |
thinsp | 8201 |
zwnj | 8204 | ‌
zwj | 8205 | ‍
lrm | 8206 | ‎
rlm | 8207 | ‏
ndash | 8211 | –
mdash | 8212 | —
lsquo | 8216 | ‘
rsquo | 8217 | ’
sbquo | 8218 | ‚
ldquo | 8220 | “
rdquo | 8221 | ”
bdquo | 8222 | „
dagger | 8224 | †
Dagger | 8225 | ‡
permil | 8240 | ‰
lsaquo | 8249 | ‹
rsaquo | 8250 | ›
euro | 8364 | €
Latin-1 (ISO-8859-1) Entities
nbsp | 160 |
iexcl | 161 | ¡
cent | 162 | ¢
pound | 163 | £
curren | 164 | ¤
yen | 165 | ¥
brvbar | 166 | ¦
sect | 167 | §
uml | 168 | ¨
copy | 169 | ©
ordf | 170 | ª
laquo | 171 | «
not | 172 | ¬
shy | 173 |
reg | 174 | ®
macr | 175 | ¯
deg | 176 | °
plusmn | 177 | ±
sup2 | 178 | ²
sup3 | 179 | ³
acute | 180 | ´
micro | 181 | µ
para | 182 | ¶
middot | 183 | ·
cedil | 184 | ¸
sup1 | 185 | ¹
ordm | 186 | º
raquo | 187 | »
frac14 | 188 | ¼
frac12 | 189 | ½
frac34 | 190 | ¾
iquest | 191 | ¿
Agrave | 192 | À
Aacute | 193 | Á
Acirc | 194 | Â
Atilde | 195 | Ã
Auml | 196 | Ä
Aring | 197 | Å
AElig | 198 | Æ
Ccedil | 199 | Ç
Egrave | 200 | È
Eacute | 201 | É
Ecirc | 202 | Ê
Euml | 203 | Ë
Igrave | 204 | Ì
Iacute | 205 | Í
Icirc | 206 | Î
Iuml | 207 | Ï
ETH | 208 | Ð
Ntilde | 209 | Ñ
Ograve | 210 | Ò
Oacute | 211 | Ó
Ocirc | 212 | Ô
Otilde | 213 | Õ
Ouml | 214 | Ö
times | 215 | ×
Oslash | 216 | Ø
Ugrave | 217 | Ù
Uacute | 218 | Ú
Ucirc | 219 | Û
Uuml | 220 | Ü
Yacute | 221 | Ý
THORN | 222 | Þ
szlig | 223 | ß
agrave | 224 | à
aacute | 225 | á
acirc | 226 | â
atilde | 227 | ã
auml | 228 | ä
aring | 229 | å
aelig | 230 | æ
ccedil | 231 | ç
egrave | 232 | è
eacute | 233 | é
ecirc | 234 | ê
euml | 235 | ë
igrave | 236 | ì
iacute | 237 | í
icirc | 238 | î
iuml | 239 | ï
eth | 240 | ð
ntilde | 241 | ñ
ograve | 242 | ò
oacute | 243 | ó
ocirc | 244 | ô
otilde | 245 | õ
ouml | 246 | ö
divide | 247 | ÷
oslash | 248 | ø
ugrave | 249 | ù
uacute | 250 | ú
ucirc | 251 | û
uuml | 252 | ü
yacute | 253 | ý
thorn | 254 | þ
yuml | 255 | ÿ
Symbols and Greek letter entities
fnof | 402 | ƒ
Alpha | 913 | Α
Beta | 914 | Β
Gamma | 915 | Γ
Delta | 916 | Δ
Epsilon | 917 | Ε
Zeta | 918 | Ζ
Eta | 919 | Η
Theta | 920 | Θ
Iota | 921 | Ι
Kappa | 922 | Κ
Lambda | 923 | Λ
Mu | 924 | Μ
Nu | 925 | Ν
Xi | 926 | Ξ
Omicron | 927 | Ο
Pi | 928 | Π
Rho | 929 | Ρ
Sigma | 931 | Σ
Tau | 932 | Τ
Upsilon | 933 | Υ
Phi | 934 | Φ
Chi | 935 | Χ
Psi | 936 | Ψ
Omega | 937 | Ω
alpha | 945 | α
beta | 946 | β
gamma | 947 | γ
delta | 948 | δ
epsilon | 949 | ε
zeta | 950 | ζ
eta | 951 | η
theta | 952 | θ
iota | 953 | ι
kappa | 954 | κ
lambda | 955 | λ
mu | 956 | μ
nu | 957 | ν
xi | 958 | ξ
omicron | 959 | ο
pi | 960 | π
rho | 961 | ρ
sigmaf | 962 | ς
sigma | 963 | σ
tau | 964 | τ
upsilon | 965 | υ
phi | 966 | φ
chi | 967 | χ
psi | 968 | ψ
omega | 969 | ω
thetasym | 977 | ϑ
upsih | 978 | ϒ
piv | 982 | ϖ
bull | 8226 | •
hellip | 8230 | …
prime | 8242 | ′
Prime | 8243 | ″
oline | 8254 | ‾
frasl | 8260 | ⁄
weierp | 8472 | ℘
image | 8465 | ℑ
real | 8476 | ℜ
trade | 8482 | ™
alefsym | 8501 | ℵ
larr | 8592 | ←
uarr | 8593 | ↑
rarr | 8594 | →
darr | 8595 | ↓
harr | 8596 | ↔
crarr | 8629 | ↵
lArr | 8656 | ⇐
uArr | 8657 | ⇑
rArr | 8658 | ⇒
dArr | 8659 | ⇓
hArr | 8660 | ⇔
forall | 8704 | ∀
part | 8706 | ∂
exist | 8707 | ∃
empty | 8709 | ∅
nabla | 8711 | ∇
isin | 8712 | ∈
notin | 8713 | ∉
ni | 8715 | ∋
prod | 8719 | ∏
sum | 8721 | ∑
minus | 8722 | −
lowast | 8727 | ∗
radic | 8730 | √
prop | 8733 | ∝
infin | 8734 | ∞
ang | 8736 | ∠
and | 8743 | ∧
or | 8744 | ∨
cap | 8745 | ∩
cup | 8746 | ∪
int | 8747 | ∫
there4 | 8756 | ∴
sim | 8764 | ∼
cong | 8773 | ≅
asymp | 8776 | ≈
ne | 8800 | ≠
equiv | 8801 | ≡
le | 8804 | ≤
ge | 8805 | ≥
sub | 8834 | ⊂
sup | 8835 | ⊃
nsub | 8836 | ⊄
sube | 8838 | ⊆
supe | 8839 | ⊇
oplus | 8853 | ⊕
otimes | 8855 | ⊗
perp | 8869 | ⊥
sdot | 8901 | ⋅
lceil | 8968 | ⌈
rceil | 8969 | ⌉
lfloor | 8970 | ⌊
rfloor | 8971 | ⌋
lang | 9001 | ⟨
rang | 9002 | ⟩
loz | 9674 | ◊
spades | 9824 | ♠
clubs | 9827 | ♣
hearts | 9829 | ♥
diams | 9830 | ♦


Application Binary Interface

Last update Sun Dec 30 20:34:43 2012

Application Binary Interface

A D implementation that conforms to the D ABI (Application Binary Interface) will be able to generate libraries, DLL's, etc., that can interoperate with D binaries built by other implementations.

C ABI

The C ABI referred to in this specification means the C Application Binary Interface of the target system. C and D code should be freely linkable together, in particular, D code shall have access to the entire C ABI runtime library.

Endianness

The endianness (byte order) of the layout of the data will conform to the endianness of the target machine. The Intel x86 CPUs are little endian meaning that the value 0x0A0B0C0D is stored in memory as: 0D 0C 0B 0A.

Basic Types

bool | 8 bit byte with the values 0 for false and 1 for true
byte | 8 bit signed value
ubyte | 8 bit unsigned value
short | 16 bit signed value
ushort | 16 bit unsigned value
int | 32 bit signed value
uint | 32 bit unsigned value
long | 64 bit signed value
ulong | 64 bit unsigned value
cent | 128 bit signed value
ucent | 128 bit unsigned value
float | 32 bit IEEE 754 floating point value
double | 64 bit IEEE 754 floating point value
real | implementation defined floating point value, for x86 it is 80 bit IEEE 754 extended real

Delegates

Delegates are fat pointers with two parts:

Delegate Layout
offset | property | contents
0 | .ptr | context pointer
ptrsize | .funcptr | pointer to function

The context pointer can be a class this reference, a struct this pointer, a pointer to a closure (nested functions) or a pointer to an enclosing function's stack frame (nested functions).

Structs

Conforms to the target's C ABI struct layout.

Classes

An object consists of:

Class Object Layout
size | property | contents
ptrsize | .__vptr | pointer to vtable
ptrsize | .__monitor | monitor
... | ... | super's non-static fields and super's interface vptrs, from least to most derived
... | named fields | non-static fields
ptrsize... |  | vptr's for any interfaces implemented by this class in left to right, most to least derived, order

The vtable consists of:

Virtual Function Pointer Table Layout
size | contents
ptrsize | pointer to instance of ClassInfo
ptrsize... | pointers to virtual member functions

Casting a class object to an interface consists of adding the offset of the interface's corresponding vptr to the address of the base of the object. Casting an interface ptr back to the class type it came from involves getting the correct offset to subtract from it from the object.Interface entry at vtbl[0]. Adjustor thunks are created and pointers to them stored in the method entries in the vtbl[] in order to set the this pointer to the start of the object instance corresponding to the implementing method.

An adjustor thunk looks like:

 ADD EAX,offset
  JMP method

The leftmost side of the inheritance graph of the interfaces all share their vptrs, this is the single inheritance model. Every time the inheritance graph forks (for multiple inheritance) a new vptr is created and stored in the class' instance. Every time a virtual method is overridden, a new vtbl[] must be created with the updated method pointers in it.

The class definition:

class XXXX {
  ....
};

Generates the following:

  • An instance of Class called ClassXXXX.
  • A type called StaticClassXXXX which defines all the static members.
  • An instance of StaticClassXXXX called StaticXXXX for the static members.

Interfaces

An interface is a pointer to a pointer to a vtbl[]. The vtbl[0] entry is a pointer to the corresponding instance of the object.Interface class. The rest of the vtbl[1..$] entries are pointers to the virtual functions implemented by that interface, in the order that they were declared.

A COM interface differs from a regular interface in that there is no object.Interface entry in vtbl[0]; the entries vtbl[0..$] are all the virtual function pointers, in the order that they were declared. This matches the COM object layout used by Windows.

Arrays

A dynamic array consists of:

Dynamic Array Layout
offset | property | contents
0 | .length | array dimension
size_t | .ptr | pointer to array data

A dynamic array is declared as:

type[] array;

whereas a static array is declared as:

type[dimension] array;

Thus, a static array always has the dimension statically available as part of the type, and so it is implemented like in C. Static array's and Dynamic arrays can be easily converted back and forth to each other.

Associative Arrays

Associative arrays consist of a pointer to an opaque, implementation defined type. The current implementation is contained in and defined by internal/aaA.d.

Reference Types

D has reference types, but they are implicit. For example, classes are always referred to by reference; this means that class instances can never reside on the stack or be passed as function parameters.

When passing a static array to a function, the result, although declared as a static array, will actually be a reference to a static array. For example:

int[3] abc;

Passing abc to functions results in these implicit conversions:

void func(int[3] array); // actually <reference to><array[3] of><int>
void func(int* p);       // abc is converted to a pointer
                         // to the first element
void func(int[] array);	 // abc is converted to a dynamic array

Name Mangling

D accomplishes typesafe linking by mangling a D identifier to include scope and type information.

MangledName:
    _D QualifiedName Type
    _D QualifiedName M Type

QualifiedName:
    SymbolName
    SymbolName QualifiedName

SymbolName:
    LName
    TemplateInstanceName

The M means that the symbol is a function that requires a this pointer.

Template Instance Names have the types and values of its parameters encoded into it:

TemplateInstanceName:
     __T LName TemplateArgs Z

TemplateArgs:
    TemplateArg
    TemplateArg TemplateArgs

TemplateArg:
    T Type
    V Type Value
    S LName

Value:
    n
    Number
    i Number
    N Number
    e HexFloat
    c HexFloat c HexFloat
    A Number Value...
    S Number Value...

HexFloat:
    NAN
    INF
    NINF
    N HexDigits P Exponent
    HexDigits P Exponent

Exponent:
    N Number
    Number

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigit:
    Digit
    A
    B
    C
    D
    E
    F
n
is for null arguments.
Number
is for positive numeric literals (including character literals).
N Number
is for negative numeric literals.
e HexFloat
is for real and imaginary floating point literals.
c HexFloat c HexFloat
is for complex floating point literals.
Width Number _ HexDigits
Width is whether the characters are 1 byte (a), 2 bytes (w) or 4 bytes (d) in size. Number is the number of characters in the string. The HexDigits are the hex data for the string.
A Number Value...
An array or asssociative array literal. Number is the length of the array. Value is repeated Number times for a normal array, and 2 * Number times for an associative array.
S Number Value...
A struct literal. Value is repeated Number times.
Name:
    Namestart
    Namestart Namechars

Namestart:
    _
    Alpha

Namechar:
    Namestart
    Digit

Namechars:
    Namechar
    Namechar Namechars

A Name is a standard D identifier.

LName:
    Number Name

Number:
    Digit
    Digit Number

Digit:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

An LName is a name preceded by a Number giving the number of characters in the Name.

Type Mangling

Types are mangled using a simple linear scheme:

Type:
    Shared
    Const
    Immutable
    Wild
    TypeArray
    TypeStaticArray
    TypeAssocArray
    TypePointer
    TypeFunction
    TypeIdent
    TypeClass
    TypeStruct
    TypeEnum
    TypeTypedef
    TypeDelegate
    TypeNone
    TypeVoid
    TypeByte
    TypeUbyte
    TypeShort
    TypeUshort
    TypeInt
    TypeUint
    TypeLong
    TypeUlong
    TypeFloat
    TypeDouble
    TypeReal
    TypeIfloat
    TypeIdouble
    TypeIreal
    TypeCfloat
    TypeCdouble
    TypeCreal
    TypeBool
    TypeChar
    TypeWchar
    TypeDchar
    TypeTuple

Shared:
    O Type

Const:
    x Type

Immutable:
    y Type

Wild:
    Ng Type

TypeArray:
    A Type

TypeStaticArray:
    G Number Type

TypeAssocArray:
    H Type Type

TypePointer:
    P Type

TypeFunction:
    CallConvention Arguments ArgClose Type

CallConvention:
    F       // D
    U       // C
    W       // Windows
    V       // Pascal
    R       // C++

Arguments:
    Argument
    Argument Arguments

Argument:
    Type
    J Type     // out
    K Type     // ref
    L Type     // lazy

ArgClose
    X     // variadic T t...) style
    Y     // variadic T t,...) style
    Z     // not variadic

TypeIdent:
    I LName

TypeClass:
    C LName

TypeStruct:
    S LName

TypeEnum:
    E LName

TypeTypedef:
    T LName

TypeDelegate:
    D TypeFunction

TypeNone:
    n

TypeVoid:
    v

TypeByte:
    g

TypeUbyte:
    h

TypeShort:
    s

TypeUshort:
    t

TypeInt:
    i

TypeUint:
    k

TypeLong:
    l

TypeUlong:
    m

TypeFloat:
    f

TypeDouble:
    d

TypeReal:
    e

TypeIfloat:
    o

TypeIdouble:
    p

TypeIreal:
    j

TypeCfloat:
    q

TypeCdouble:
    r

TypeCreal:
    c

TypeBool:
    b

TypeChar:
    a

TypeWchar:
    u

TypeDchar:
    w

TypeTuple:
    B Number Arguments

Function Calling Conventions

The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system. Except that the extern (D) calling convention for Windows x86 is described here.

Register Conventions

  • EAX, ECX, EDX are scratch registers and can be destroyed by a function.
  • EBX, ESI, EDI, EBP must be preserved across function calls.
  • EFLAGS is assumed destroyed across function calls, except for the direction flag which must be forward.
  • The FPU stack must be empty when calling a function.
  • The FPU control word must be preserved across function calls.
  • Floating point return values are returned on the FPU stack. These must be cleaned off by the caller, even if they are not used.

Return Value

  • The types bool, byte, ubyte, short, ushort, int, uint, pointer, Object, and interfaces are returned in EAX.
  • long and ulong are returned in EDX,EAX, where EDX gets the most significant half.
  • float, double, real, ifloat, idouble, ireal are returned in ST0.
  • cfloat, cdouble, creal are returned in ST1,ST0 where ST1 is the real part and ST0 is the imaginary part.
  • Dynamic arrays are returned with the pointer in EDX and the length in EAX.
  • Associative arrays are returned in EAX with garbage returned in EDX. The EDX value will probably be removed in the future; it's there for backwards compatibility with an earlier implementation of AA's.
  • Delegates are returned with the pointer to the function in EDX and the context pointer in EAX.
  • 1, 2 and 4 byte structs are returned in EAX.
  • 8 byte structs are returned in EDX,EAX, where EDX gets the most significant half.
  • For other struct sizes, the return value is stored through a hidden pointer passed as an argument to the function.
  • Constructors return the this pointer in EAX.

Parameters

The parameters to the non-variadic function:

    foo(a1, a2, ..., an);

are passed as follows:

a1
a2
...
an
hidden
this

where hidden is present if needed to return a struct value, and this is present if needed as the this pointer for a member function or the context pointer for a nested function.

The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met:

  • It fits in EAX.
  • It is not a 3 byte struct.
  • It is not a floating point type.

Parameters are always pushed as multiples of 4 bytes, rounding upwards, so the stack is always aligned on 4 byte boundaries. They are pushed most significant first. out and ref are passed as pointers. Static arrays are passed as pointers to their first element. On Windows, a real is pushed as a 10 byte quantity, a creal is pushed as a 20 byte quantity. On Linux, a real is pushed as a 12 byte quantity, a creal is pushed as two 12 byte quantities. The extra two bytes of pad occupy the ‘most significant’ position.

The callee cleans the stack.

The parameters to the variadic function:

    void foo(int p1, int p2, int[] p3...)
    foo(a1, a2, ..., an);

are passed as follows:

p1
p2
a3
hidden
this

The variadic part is converted to a dynamic array and the rest is the same as for non-variadic functions.

The parameters to the variadic function:

    void foo(int p1, int p2, ...)
    foo(a1, a2, a3, ..., an);

are passed as follows:

an
...
a3
a2
a1
_arguments
hidden
this

The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee.

Exception Handling

Windows

Conforms to the Microsoft Windows Structured Exception Handling conventions.

Linux

FreeBSD and OS X,

Uses static address range/handler tables. It is not compatible with the ELF/Mach-O exception handling tables. The stack is walked assuming it uses the EBP/RBP stack frame convention. The EBP/RBP convention must be used for every function that has an associated EH (Exception Handler) table.

For each function that has exception handlers, an EH table entry is generated.

EH Table Entry
field | description
void* | pointer to start of function
DHandlerTable* | pointer to corresponding EH data
uint | size in bytes of the function

The EH table entries are placed into the following special segments, which are concatenated by the linker.

EH Table Segment
Operating System | Segment Name
Windows | FI
Linux | .deh_eh
FreeBSD | .deh_eh
OS X | __deh_eh, __DATA

The rest of the EH data can be placed anywhere, it is immutable.

DHandlerTable
field | description
void* | pointer to start of function
uint | offset of ESP/RSP from EBP/RBP
uint | offset from start of function to return code
uint | number of entries in DHandlerInfo[]
DHandlerInfo[] | array of handler information

DHandlerInfo
field | description
uint | offset from function address to start of guarded section
uint | offset of end of guarded section
int | previous table index
uint | if != 0 offset to DCatchInfo data from start of table
void* | if not null, pointer to finally code to execute

DCatchInfo
field | description
uint | number of entries in DCatchBlock[]
DCatchBlock[] | array of catch information

DCatchBlock
field | description
ClassInfo | catch type
uint | offset from EBP/RBP to catch variable
void* | catch handler code

Garbage Collection

The interface to this is found in phobos/internal/gc.

Runtime Helper Functions

These are found in phobos/internal.

Module Initialization and Termination

All the static constructors for a module are aggregated into a single function, and a pointer to that function is inserted into the ctor member of the ModuleInfo instance for that module.

All the static denstructors for a module are aggregated into a single function, and a pointer to that function is inserted into the dtor member of the ModuleInfo instance for that module.

Unit Testing

All the unit tests for a module are aggregated into a single function, and a pointer to that function is inserted into the unitTest member of the ModuleInfo instance for that module.

Symbolic Debugging

D has types that are not represented in existing C or C++ debuggers. These are dynamic arrays, associative arrays, and delegates. Representing these types as structs causes problems because function calling conventions for structs are often different than that for these types, which causes C/C++ debuggers to misrepresent things. For these debuggers, they are represented as a C type which does match the calling conventions for the type. The dmd compiler will generate only C symbolic type info with the -gc compiler switch.

Types for C Debuggers
D type | C representation
dynamic array | unsigned long long
associative array | void*
delegate | long long
dchar | unsigned long

For debuggers that can be modified to accept new types, the following extensions help them fully support the types.

Codeview Debugger Extensions

The D dchar type is represented by the special primitive type 0x78.

D makes use of the Codeview OEM generic type record indicated by LF_OEM (0x0015). The format is:

Codeview OEM Extensions for D
field size | 2 | 2 | 2 | 2 | 2 | 2
D Type | Leaf Index | OEM Identifier | recOEM | num indices | type index | type index
dynamic array | LF_OEM | OEM | 1 | 2 | @index | @element
associative array | LF_OEM | OEM | 2 | 2 | @key | @element
delegate | LF_OEM | OEM | 3 | 2 | @this | @function

Where:

OEM | 0x42
index | type index of array index
key | type index of key
element | type index of array element
this | type index of context pointer
function | type index of function

These extensions can be pretty-printed by obj2asm.

The Ddbg debugger supports them.

Dwarf Debugger Extensions

The following leaf types are added:

Dwarf Extensions for D
D type | Identifier | Value | Format
dynamic array | DW_TAG_darray_type | 0x41 | DW_AT_type is element type
associative array | DW_TAG_aarray_type | 0x42 | DW_AT_type, is element type, DW_AT_containing_type key type
delegate | DW_TAG_delegate_type | 0x43 | DW_AT_type, is function type, DW_AT_containing_type is ‘this’ type

These extensions can be pretty-printed by dumpobj.

The ZeroBUGS debugger supports them.

Note that these Dwarf extensions have been removed as they conflict with recent gcc additions.


Phobos Runtime Library

Phobos is the standard runtime library that comes with the D language compiler. Also, check out the wiki for Phobos.

Philosophy

Each module in Phobos conforms as much as possible to the following design goals. These are goals rather than requirements because D is not a religion, it's a programming language, and it recognizes that sometimes the goals are contradictory and counterproductive in certain situations, and programmers have jobs that need to get done.
Machine and Operating System Independent Interfaces
It's pretty well accepted that gratuitous non-portability should be avoided. This should not be construed, however, as meaning that access to unusual features of an operating system should be prevented.
Simple Operations should be Simple
A common and simple operation, like writing an array of bytes to a file, should be simple to code. I haven't seen a class library yet that simply and efficiently implemented common, basic file I/O operations.
Classes should strive to be independent of one another
It's discouraging to pull in a megabyte of code bloat by just trying to read a file into an array of bytes. Class independence also means that classes that turn out to be mistakes can be deprecated and redesigned without forcing a rewrite of the rest of the class library.
No pointless wrappers around C runtime library functions or OS API functions
D provides direct access to C runtime library functions and operating system API functions. Pointless D wrappers around those functions just adds blather, bloat, baggage and bugs.
Class implementations should use DBC
This will prove that DBC (Contract Programming) is worthwhile. Not only will it aid in debugging the class, but it will help every class user use the class correctly. DBC in the class library will have great leverage.
Use Exceptions for Error Handling
See Error Handling in D.

Imports

Runtime library modules can be imported with the import statement. Each module falls into one of several packages:
std
These are the core modules.

std.windows
Modules specific to the Windows operating system.

std.linux
Modules specific to the Linux operating system.

std.c
Modules that are simply interfaces to C functions. For example, interfaces to standard C library functions will be in std.c, such as std.c.stdio would be the interface to C's stdio.h.

std.c.windows
Modules corresponding to the C Windows API functions.

std.c.linux
Modules corresponding to the C Linux API functions.

etc
This is the root of a hierarchy of modules mirroring the std hierarchy. Modules in etc are not standard D modules. They are here because they are experimental, or for some other reason are not quite suitable for std, although they are still useful.

std: Core library modules
std.base64
Encode/decode base64 format.
std.bind
Bind function arguments.
std.bitarray
Arrays of bits.
std.boxer
Box/unbox types.
std.compiler
Information about the D compiler implementation.
std.conv
Conversion of strings to integers.
std.ctype
Simple character classification
std.date
Date and time functions. Support locales.
std.file
Basic file operations like read, write, append.
std.format
Formatted conversions of values to strings.
std.gc
Control the garbage collector.
std.intrinsic
Compiler built in intrinsic functions
std.math
Include all the usual math functions like sin, cos, atan, etc.
std.md5
Compute MD5 digests.
std.mmfile
Memory mapped files.
object
The root class of the inheritance hierarchy
std.openrj
Basic database.
std.outbuffer
Assemble data into an array of bytes
std.path
Manipulate file names, path names, etc.
std.process
Create/destroy threads.
std.random
Random number generation.
std.recls
Recursively search file system and (currently Windows only) FTP sites.
std.regexp
The usual regular expression functions.
std.socket
Sockets.
std.socketstream
Stream for a blocking, connected Socket.
std.stdint
Integral types for various purposes.
std.stdio
Standard I/O.
std.cstream
Stream I/O.
std.stream
Stream I/O.
std.string
Basic string operations not covered by array ops.
std.system
Inquire about the CPU, operating system.
std.thread
One per thread. Operations to do on a thread.
std.uri
Encode and decode Uniform Resource Identifiers (URIs).
std.utf
Encode and decode utf character encodings.
std.zip
Read/write zip archives.
std.zlib
Compression / Decompression of data.

std.windows: Modules specific to the Windows operating system
std.windows.syserror
Convert Windows error codes to strings.

std.linux: Modules specific to the Linux operating system

std.c: Interface to C functions
std.c.stdio
Interface to C stdio functions like printf().

std.c.windows: Interface to C Windows functions
std.c.windows.windows
Interface to Windows APIs

std.c.linux: Interface to C Linux functions
std.c.linux.linux
Interface to Linux APIs

std.c.stdio
int printf(char* format, ...)
C printf() function.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


object

Part of the D programming language runtime library. Forms the symbols available to all D programs. Includes Object, which is the root of the class object hierarchy.

This module is implicitly imported.

Source:
internal/object.d

alias size_t;
An unsigned integral type large enough to span the memory space. Use for array indices and pointer offsets for maximal portability to architectures that have different memory address ranges. This is analogous to C's size_t.

alias ptrdiff_t;
A signed integral type large enough to span the memory space. Use for pointer differences and for size_t differences for maximal portability to architectures that have different memory address ranges. This is analogous to C's ptrdiff_t.

alias c_long;
Handy alias's for C's long and unsigned long types, which vary in size.

alias c_ulong;
Handy alias's for C's long and unsigned long types, which vary in size.

alias bit;
Standard boolean type.

class Object;
All D class objects inherit from Object.

void print();
Converts Object to human readable text and writes it to stdout.

char[] toString();
Convert Object to a human readable string.

hash_t toHash();
Compute hash function for Object.

int opCmp(Object o);
Compare with another Object obj.

Returns:
this < obj | < 0
this == obj | 0
this > obj | > 0

int opEquals(Object o);
Returns !=0 if this object does have the same contents as obj.

static Object factory(char[] classname);
Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

Returns:
null if failed

struct Interface;
Information about an interface. When an object is accessed via an interface, an Interface* appears as the first entry in its vtbl.

ClassInfo classinfo;
.classinfo for this interface (not for containing class)

int offset;
offset to Interface 'this' from Object 'this'

class ClassInfo;
Runtime type information about a class. Can be retrieved for any class type or instance by using the .classinfo property. A pointer to this appears as the first entry in the class's vtbl[].

byte[] init;
class static initializer (init.length gives size in bytes of class)

char[] name;
class name

void*[] vtbl;
virtual function pointer table

Interface[] interfaces;
interfaces this class implements

ClassInfo base;
base class

static ClassInfo find(char[] classname);
Search all modules for ClassInfo corresponding to classname.

Returns:
null if not found

Object create();
Create instance of Object represented by 'this'.

Returns:
the object created, or null if the Object does does not have a default constructor

struct OffsetTypeInfo;
Array of pairs giving the offset and type information for each member in an aggregate.

size_t offset;
Offset of member from start of object

TypeInfo ti;
TypeInfo for this member

class TypeInfo;
Runtime type information about a type. Can be retrieved for any type using a TypeidExpression.

hash_t getHash(void* p);
Returns a hash of the instance of a type.

int equals(void* p1, void* p2);
Compares two instances for equality.

int compare(void* p1, void* p2);
Compares two instances for <, ==, or >.

size_t tsize();
Returns size of the type.

void swap(void* p1, void* p2);
Swaps two instances of the type.

TypeInfo next();
Get TypeInfo for 'next' type, as defined by what kind of type this is, null if none.

void[] init();
Return default initializer. If the type should be initialized to all zeros, an array with a null ptr and a length equal to the type size will be returned.

uint flags();
Get flags for type: 1 means GC should scan for pointers

OffsetTypeInfo[] offTi();
Get type information on the contents of the type; null if not available

size_t talign();
Return alignment of type

class Exception;
All recoverable exceptions should be derived from class Exception.

this(char[] msg);
Constructor; msg is a descriptive message for the exception.

class Error: object.Exception;
All irrecoverable exceptions should be derived from class Error.

this(char[] msg);
Constructor; msg is a descriptive message for the exception.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.base64

Encodes/decodes MIME base64 data.

Source:
std/base64.d

References:
Wikipedia Base64
RFC 2045

class Base64Exception: object.Exception;

class Base64CharException: std.base64.Base64Exception;

size_t encodeLength(size_t slen);
Returns the number of bytes needed to encode a string of length slen.

char[] encode(char[] str, char[] buf);
Encodes str[] and places the result in buf[].

Params:
char[] str | string to encode
char[] buf | destination buffer, must be large enough for the result.

Returns:
slice into buf[] representing encoded result

char[] encode(char[] str);
Encodes str[] and returns the result.

size_t decodeLength(size_t elen);
Returns the number of bytes needed to decode an encoded string of this length.

char[] decode(char[] estr, char[] buf);
Decodes str[] and places the result in buf[].

Params:
str | string to encode
char[] buf | destination buffer, must be large enough for the result.

Returns:
slice into buf[] representing encoded result

Errors:
Throws Base64Exception on invalid base64 encoding in estr[]. Throws Base64CharException on invalid base64 character in estr[].

char[] decode(char[] estr);
Decodes estr[] and returns the result.

Errors:
Throws Base64Exception on invalid base64 encoding in estr[]. Throws Base64CharException on invalid base64 character in estr[].

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.bind

Bind function arguments to functions.

References:
boost::bind

Authors:
Tomasz Stachowiak

Date:
November 28, 2006

Source:
std/bind.d

DynArg!(0) _0;
DynArg!(1) _1;
DynArg!(2) _2;
DynArg!(3) _3;
DynArg!(4) _4;
DynArg!(5) _5;
DynArg!(6) _6;
DynArg!(7) _7;
DynArg!(8) _8;
DynArg!(9) _9;
When passed to the 'bind' function, they will mark dynamic params - ones that aren't statically bound In boost, they're called _1, _2, _3, etc.. here _0, _1, _2, ...

struct Tuple(T...);
A simple tuple struct with some basic operations

template appendT(X)
Statically yields a tuple type with an extra element added at its end

appendT!(X) append(X)(X x);
Yields a tuple with an extra element added at its end

template prependT(X)
Statically yields a tuple type with an extra element added at its beginning

prependT!(X) prepend(X)(X x);
Yields a tuple with an extra element added at its beginning

template concatT(T...)
Statically concatenates this tuple type with another tuple type

struct Tuple();
An empty tuple struct

alias type;
an empty built-in tuple

alias value;
an empty built-in tuple

Tuple!(T) tuple(T...)(T t);
Dynamically create a tuple from the given items

template isTypeTuple(T)
Checks whether a given type is the Tuple struct of any length

template minNumArgs(alias fn,fnT = typeof(&fn))
Finds the minimal number of arguments a given function needs to be provided

class BoundFunc(FT,alias FAlias_,AllBoundArgs_);
A context for bound/curried functions

typeof(new BoundFunc!(FT,NullAlias,Tuple!(ArgList))) bind(FT, ArgList...)(FT fp, ArgList args);
bind() can curry or "bind" arguments of a function, producing a different function which requires less parameters, or a different order of parameters. It also allows function composition.

The syntax of a bind() call is:

bind(function or delegate pointer { , argument });

argument can be one of:
  • static/bound argument (an immediate value)
  • another bound function object
  • dynamic argument, of the form _[0-9], e.g. _0, _3 or _9

The result is a function object, which can be called using call(), func() or opCall(). There also exists a convenience function, ptr() which returns a delegate to call/func/opCall

The resulting delegate accepts exactly as many parameters as many distinct dynamic arguments were used.
- bind(&foo, _0, _1) // will yield a delegate accepting two parameters
- bind(&foo, _1, _0) // will yield a delegate accepting two parameters
- bind(&bar, _0, _1, _2, _0) // will yield a delegate accepting three parameters

The types of dynamic parameters are extracted from the bound function itself and when necessary, type negotiation is performed. For example, binding a function
void foo(int a, long b)

// with:
bind(&foo, _0, _0)
will result in a delegate accepting a single, optimal parameter type. The best type is computed using std.typetuple.DerivedToFront, so in case of an int and a long, long will be selected. Generally, bind will try to find a type that can be implicitly converted to all the other types a given dynamic parameter uses.

Note:
in case of numeric types, an explicit, but transparent (to the user) cast will be performed

Function composition works intuitively:
bind(&f1, bind(&f2, _0))

which will yield a delegate, that takes the argument, calls f2, then uses the return value of f2 to call f1. Mathematically speaking, it will yield a function composition:
f1(f2(_0))

When one function is composed multiple times, it will be called multiple times - Bind does no lazy evaluation, so
bind(&f3, bind(&f4, _0), bind(&f4, _0))
will produce a delegate, which, upon calling, will invoke f4 two times to evaluate the arguments for f3 and then call f3

One another feature that bind() supports is automatic tuple expansion. It means that having functions:
void foo(int a, int b)
Tuple!(int, int) bar()

Allows them to be bound by writing:
bind(&foo, bind(&bar))
// or
bind(&foo, tuple(23, 45))

template bindAlias(alias FT)
bindAlias() is similar to bind(), but it's more powerful. Use bindAlias() rather than bind() where possible.

The syntax is:

bindAlias!(Function)(argument, argument, argument, argument, ...);

bindAlias takes advantage of using aliases directly, thus being able to extract default values from functions and not forcing the user to bind them. It doesn't, however mean that the resulting delegate can be called, omitting some of its parameters. It only means that these arguments that have default values in the function provided to bindAlias don't have to be bound explicitly.

Additionally, bindAlias takes care of functions with out/inout parameters, by converting them to pointers internally. A function like:
void foo(inout a)
can be bound using:
int x;
bindAlias!(foo)(&x);

Note:
there is no bind-time check for reference nullness, there is however a call-time check on all references which can be disabled by using version=BindNoNullCheck or compiling in release mode.

Public Domain | Page generated by Ddoc.


std.bitarray

Source:
std/bitarray.d

struct BitArray;
An array of bits.

bool opIndex(size_t i);
bool opIndexAssign(bool b, size_t i);
Support for [index] operation for BitArray.

BitArray dup();
Support for array.dup property for BitArray.

int opApply(int delegate(ref bool) dg);
int opApply(int delegate(ref uint, ref bool) dg);
Support for foreach loops for BitArray.

BitArray reverse();
Support for array.reverse property for BitArray.

BitArray sort();
Support for array.sort property for BitArray.

int opEquals(BitArray a2);
Support for operators == and != for bit arrays.

int opCmp(BitArray a2);
Implement comparison operators.

void init(bool[] ba);
Set BitArray to contents of ba[]

void init(void[] v, size_t numbits);
Map BitArray onto v[], with numbits being the number of bits in the array. Does not copy the data.

This is the inverse of opCast.

void[] opCast();
Convert to void[].

BitArray opCom();
Support for unary operator ~ for bit arrays.

BitArray opAnd(BitArray e2);
Support for binary operator & for bit arrays.

BitArray opOr(BitArray e2);
Support for binary operator | for bit arrays.

BitArray opXor(BitArray e2);
Support for binary operator ^ for bit arrays.

BitArray opSub(BitArray e2);
Support for binary operator - for bit arrays.

a - b for BitArrays means the same thing as a & ~b.

BitArray opAndAssign(BitArray e2);
Support for operator &= bit arrays.

BitArray opOrAssign(BitArray e2);
Support for operator |= for bit arrays.

BitArray opXorAssign(BitArray e2);
Support for operator ^= for bit arrays.

BitArray opSubAssign(BitArray e2);
Support for operator -= for bit arrays.

a -= b for BitArrays means the same thing as a &= ~b.

BitArray opCatAssign(bool b);
BitArray opCatAssign(BitArray b);
Support for operator ~= for bit arrays.

BitArray opCat(bool b);
BitArray opCat_r(bool b);
BitArray opCat(BitArray b);
Support for binary operator ~ for bit arrays.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.boxer

This module is a set of types and functions for converting any object (value or heap) into a generic box type, allowing the user to pass that object around without knowing what's in the box, and then allowing him to recover the value afterwards.

Example:
// Convert the integer 45 into a box.
Box b = box(45);

// Recover the integer and cast it to real.
real r = unbox!(real)(b);

That is the basic interface and will usually be all that you need to understand. If it cannot unbox the object to the given type, it throws UnboxException. As demonstrated, it uses implicit casts to behave in the exact same way that static types behave. So for example, you can unbox from int to real, but you cannot unbox from real to int: that would require an explicit cast.

This therefore means that attempting to unbox an int as a string will throw an error instead of formatting it. In general, you can call the toString method on the box and receive a good result, depending upon whether std.string.format accepts it.

Boxes can be compared to one another and they can be used as keys for associative arrays.

There are also functions for converting to and from arrays of boxes.

Example:
// Convert arguments into an array of boxes.
Box[] a = boxArray(1, 45.4, "foobar");

// Convert an array of boxes back into arguments.
TypeInfo[] arg_types;
void* arg_data;

boxArrayToArguments(a, arg_types, arg_data);

// Convert the arguments back into boxes using a
// different form of the function.
a = boxArray(arg_types, arg_data);
One use of this is to support a variadic function more easily and robustly; simply call "boxArray(arguments, argptr)", then do whatever you need to do with the array.

Authors:
Burton Radons

License:
Public Domain

BUGS:
  • Bugzilla 309
  • Bugzilla 1968

Source:
std/boxer.d

enum TypeClass;
The type class returned from Box.findTypeClass; the order of entries is important.

Bool
< bool

Integer
< byte, ubyte, short, ushort, int, uint, long, ulong

Float
< float, double, real

Complex
< cfloat, cdouble, creal

Imaginary
< ifloat, idouble, ireal

Class
< Inherits from Object

Pointer
< Pointer type (T *)

Array
< Array type (T [])

Other
< Any other type, such as delegates, function pointers, struct, void...

struct Box;
Box is a generic container for objects (both value and heap), allowing the user to box them in a generic form and recover them later. A box object contains a value in a generic fashion, allowing it to be passed from one place to another without having to know its type. It is created by calling the box function, and you can recover the value by instantiating the unbox template.

bool unboxable(TypeInfo test);
Return whether this value could be unboxed as the given type without throwing.

TypeInfo type();
Property for the type contained by the box. This is initially null and cannot be assigned directly.

Returns:
the type of the contained object.

void[] data();
Property for the data pointer to the value of the box. This is initially null and cannot be assigned directly.

Returns:
the data array.

char[] toString();
Attempt to convert the boxed value into a string using std.string.format; this will throw if that function cannot handle it. If the box is uninitialized then this returns "".

bool opEquals(Box other);
Compare this box's value with another box. This implicitly casts if the types are different, identical to the regular type system.

float opCmp(Box other);
Compare this box's value with another box. This implicitly casts if the types are different, identical to the regular type system.

hash_t toHash();
Return the value's hash.

Box box(...);
Box the single argument passed to the function. If more or fewer than one argument is passed, this will assert.

Box box(TypeInfo type, void* data);
Box the explicitly-defined object. type must not be null; data must not be null if the type's size is greater than zero. The data is copied.

Box[] boxArray(TypeInfo[] types, void* data);
Convert a list of arguments into a list of boxes.

Box[] boxArray(...);
Box each argument passed to the function, returning an array of boxes.

void boxArrayToArguments(Box[] arguments, out TypeInfo[] types, out void* data);
Convert an array of boxes into an array of arguments.

class UnboxException: object.Exception;
This class is thrown if unbox is unable to cast the value into the desired result.

Box object;
This is the box that the user attempted to unbox.

TypeInfo outputType;
This is the type that the user attempted to unbox the value as.

this(Box object, TypeInfo outputType);
Assign parameters and create the message in the form "Could not unbox from type ... to ... ."

T unboxCastReal(T)(Box value);
A generic unboxer for the real numeric types.

T unboxCastInteger(T)(Box value);
A generic unboxer for the integral numeric types.

T unboxCastComplex(T)(Box value);
A generic unboxer for the complex numeric types.

T unboxCastImaginary(T)(Box value);
A generic unboxer for the imaginary numeric types.

T unbox(T)(Box value);
The unbox template takes a type parameter and returns a function that takes a box object and returns the specified type.

To use it, instantiate the template with the desired result type, and then call the function with the box to convert. This will implicitly cast base types as necessary and in a way consistent with static types - for example, it will cast a boxed byte into int, but it won't cast a boxed float into short.

Throws:
UnboxException if it cannot cast

Example:
 Box b = box(4.5);
 bit u = unboxable!(real)(b); // This is true.
 real r = unbox!(real)(b);

 Box y = box(4);
 int x = unbox!(int) (y);

bool unboxable(T)(Box value);
Return whether the value can be unboxed as the given type; if this returns false, attempting to do so will throw UnboxException.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.compiler

Source:
std/compiler.d

Authors:
Walter Bright, www.digitalmars.com

License:
Public Domain

const string name;
Vendor specific string naming the compiler, for example: "Digital Mars D".

enum Vendor;
Master list of D compiler vendors.

DigitalMars
Digital Mars

const Vendor vendor;
Which vendor produced this compiler.

const uint version_major;
const uint version_minor;
The vendor specific version number, as in version_major.version_minor

const uint D_major;
The version of the D Programming Language Specification supported by the compiler.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.conv

Conversion building blocks. These differ from the C equivalents atoi() and atol() by checking for overflow and not allowing whitespace.

For conversion to signed types, the grammar recognized is:
Integer:
    Sign UnsignedInteger
    UnsignedInteger

Sign:
    +
    -
For conversion to signed types, the grammar recognized is:
UnsignedInteger:
    DecimalDigit
    DecimalDigit UnsignedInteger

Source:
std/conv.d

class ConvError: object.Error;
Thrown on conversion errors, which happens on deviation from the grammar.

class ConvOverflowError: object.Error;
Thrown on conversion overflow errors.

int toInt(char[] s);
uint toUint(char[] s);
long toLong(char[] s);
ulong toUlong(char[] s);
short toShort(char[] s);
ushort toUshort(char[] s);
byte toByte(char[] s);
ubyte toUbyte(char[] s);
float toFloat(char[] s);
double toDouble(char[] s);
real toReal(char[] s);
Convert character string to the return type.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.cover

Code coverage analyzer.

BUGS:
  • the execution counters are 32 bits in size, and can overflow
  • inline asm statements are not counted

Source:
std/cover.d

void setSourceDir(string pathname);
Set path to where source files are located.

void setDestDir(string pathname);
Set path to where listing files are to be written.

void setMerge(bool flag);
Set merge mode.

Params:
bool flag true means new data is summed with existing data in the listing file; false means a new listing file is always created.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.cpuid

Identify the characteristics of the host CPU.

Implemented according to:

- AP-485 Intel(C) Processor Identification and the CPUID Instruction http://www.intel.com/design/xeon/applnots/241618.htm

- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M http://developer.intel.com/design/pentium4/manuals/index_new.htm

- AMD CPUID Specification Publication # 25481 http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf

Example:
import std.cpuid;
import std.stdio;

void main()
{
    writefln(std.cpuid.toString());
}

Authors:
Tomas Lindquist Olsen <tomas@famolsen.dk> (slightly altered by Walter Bright)

BUGS:
Only works on x86 CPUs

Source:
std/cpuid.d

char[] toString();
Returns everything as a printable string

char[] vendor();
Returns vendor string

char[] processor();
Returns processor string

bool mmx();
Is MMX supported?

bool fxsr();
Is FXSR supported?

bool sse();
Is SSE supported?

bool sse2();
Is SSE2 supported?

bool sse3();
Is SSE3 supported?

bool ssse3();
Is SSSE3 supported?

bool amd3dnow();
Is AMD 3DNOW supported?

bool amd3dnowExt();
Is AMD 3DNOW Ext supported?

bool amdMmx();
Is AMD MMX supported?

bool ia64();
Is this an Intel Architecture IA64?

bool amd64();
Is this an AMD 64?

bool hyperThreading();
Is hyperthreading supported?

uint threadsPerCPU();
Returns number of threads per CPU

uint coresPerCPU();
Returns number of cores in CPU

bool intel();
Is this an Intel processor?

bool amd();
Is this an AMD processor?

uint stepping();
Returns stepping

uint model();
Returns model

uint family();
Returns family

Public Domain | Page generated by Ddoc.


std.ctype

Simple ASCII character classification functions. For Unicode classification, see std.uni.

References:
ASCII Table, Wikipedia

Source:
std/ctype.d

int isalnum(dchar c);
Returns !=0 if c is a letter in the range (0..9, a..z, A..Z).

int isalpha(dchar c);
Returns !=0 if c is an ascii upper or lower case letter.

int iscntrl(dchar c);
Returns !=0 if c is a control character.

int isdigit(dchar c);
Returns !=0 if c is a digit.

int islower(dchar c);
Returns !=0 if c is lower case ascii letter.

int ispunct(dchar c);
Returns !=0 if c is a punctuation character.

int isspace(dchar c);
Returns !=0 if c is a space, tab, vertical tab, form feed, carriage return, or linefeed.

int isupper(dchar c);
Returns !=0 if c is an upper case ascii character.

int isxdigit(dchar c);
Returns !=0 if c is a hex digit (0..9, a..f, A..F).

int isgraph(dchar c);
Returns !=0 if c is a printing character except for the space character.

int isprint(dchar c);
Returns !=0 if c is a printing character including the space character.

int isascii(dchar c);
Returns !=0 if c is in the ascii character set, i.e. in the range 0..0x7F.

dchar tolower(dchar c);
If c is an upper case ascii character, return the lower case equivalent, otherwise return c.

dchar toupper(dchar c);
If c is a lower case ascii character, return the upper case equivalent, otherwise return c.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.date

Dates are represented in several formats. The date implementation revolves around a central type, d_time, from which other formats are converted to and from. Dates are calculated using the Gregorian calendar.

References:
Gregorian calendar (Wikipedia)

Source:
std/date.d

License:
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Boost License 1.0)

Authors:
Walter Bright

alias d_time;
is a signed arithmetic type giving the time elapsed since January 1, 1970. Negative values are for dates preceding 1970. The time unit used is Ticks. Ticks are milliseconds or smaller intervals.

The usual arithmetic operations can be performed on d_time, such as adding, subtracting, etc. Elapsed time in Ticks can be computed by subtracting a starting d_time from an ending d_time.

const d_time d_time_nan;
A value for d_time that does not represent a valid time.

struct Date;
Time broken down into its components.

int year;
use int.min as "nan" year value

int month;
1..12

int day;
1..31

int hour;
0..23

int minute;
0..59

int second;
0..59

int ms;
0..999

int weekday;
0: not specified, 1..7: Sunday..Saturday

int tzcorrection;
-1200..1200 correction in hours

void parse(string s);
Parse date out of string s[] and store it in this Date instance.

TicksPerSecond
Will be at least 1000

void toISO8601YearWeek(d_time t, out int year, out int week);
Compute year and week [1..53] from t. The ISO 8601 week 1 is the first week of the year that includes January 4. Monday is the first day of the week.

References:
ISO 8601 (Wikipedia)

int YearFromTime(d_time t);
Calculates the year from the d_time t.

int inLeapYear(d_time t);
Determines if d_time t is a leap year.

A leap year is every 4 years except years ending in 00 that are not divsible by 400.

Returns:
!=0 if it is a leap year.

References:
Wikipedia

int MonthFromTime(d_time t);
Calculates the month from the d_time t.

Returns:
Integer in the range 0..11, where 0 represents January and 11 represents December.

int DateFromTime(d_time t);
Compute which day in a month a d_time t is.

Returns:
Integer in the range 1..31

int WeekDay(d_time t);
Compute which day of the week a d_time t is.

Returns:
Integer in the range 0..6, where 0 represents Sunday and 6 represents Saturday.

d_time UTCtoLocalTime(d_time t);
Convert from UTC to local time.

d_time LocalTimetoUTC(d_time t);
Convert from local time to UTC.

int DateFromNthWeekdayOfMonth(int year, int month, int weekday, int n);
Determine the date in the month, 1..31, of the nth weekday.

Params:
int year | year
int month | month, 1..12
int weekday | day of week 0..6 representing Sunday..Saturday
int n | nth occurrence of that weekday in the month, 1..5, where 5 also means "the last occurrence in the month"

Returns:
the date in the month, 1..31, of the nth weekday

int daysInMonth(int year, int month);
Determine the number of days in a month, 1..31.

Params:
int month 1..12

string toString(d_time time);
Converts UTC time into a text string of the form: "Www Mmm dd hh:mm:ss GMT+-TZ yyyy". For example, "Tue Apr 02 02:04:57 GMT-0800 1996". If time is invalid, i.e. is d_time_nan, the string "Invalid date" is returned.

Example:
  d_time lNow;
  char[] lNowString;

  // Grab the date and time relative to UTC
  lNow = std.date.getUTCtime();
  // Convert this into the local date and time for display.
  lNowString = std.date.toString(lNow);

string toUTCString(d_time t);
Converts t into a text string of the form: "Www, dd Mmm yyyy hh:mm:ss UTC". If t is invalid, "Invalid date" is returned.

string toDateString(d_time time);
Converts the date portion of time into a text string of the form: "Www Mmm dd yyyy", for example, "Tue Apr 02 1996". If time is invalid, "Invalid date" is returned.

string toTimeString(d_time time);
Converts the time portion of t into a text string of the form: "hh:mm:ss GMT+-TZ", for example, "02:04:57 GMT-0800". If t is invalid, "Invalid date" is returned. The input must be in UTC, and the output is in local time.

d_time parse(string s);
Parses s as a textual date string, and returns it as a d_time. If the string is not a valid date, is returned.

d_time getUTCtime();
Get current UTC time.

typedef DosFileTime;
Type representing the DOS file date/time format.

d_time toDtime(DosFileTime time);
Convert from DOS file date/time to d_time.

DosFileTime toDosFileTime(d_time t);
Convert from d_time to DOS file date/time.

Copyright Digital Mars 2000 - 2010. | Page generated by Ddoc.


std.demangle

Demangle D mangled names.

Source:
std/demangle.d

string demangle(string name);
Demangle D mangled names.

If it is not a D mangled name, it returns its argument name.

Example:
This program reads standard in and writes it to standard out, pretty-printing any found D mangled names.
import std.stdio;
import std.ctype;
import std.demangle;

int main()
{   char[] buffer;
    bool inword;
    int c;

    while ((c = fgetc(stdin)) != EOF)
    {
        if (inword)
        {
            if (c == '_' || isalnum(c))
                buffer ~= cast(char) c;
            else
            {
                inword = false;
                writef(demangle(buffer), cast(char) c);
            }
        }
        else
        {   if (c == '_' || isalpha(c))
            {   inword = true;
                buffer.length = 0;
                buffer ~= cast(char) c;
            }
            else
                writef(cast(char) c);
        }
    }
    if (inword)
        writef(demangle(buffer));
    return 0;
}

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.file

Source:
std/file.d

class FileException: object.Exception;
Exception thrown for file I/O errors.

void[] read(char[] name);
Read file name[], return array of bytes read.

Throws:
FileException on error.

void write(char[] name, void[] buffer);
Write buffer[] to file name[].

Throws:
FileException on error.

void append(char[] name, void[] buffer);
Append buffer[] to file name[].

Throws:
FileException on error.

void rename(char[] from, char[] to);
Rename file from[] to to[].

Throws:
FileException on error.

void remove(char[] name);
Delete file name[].

Throws:
FileException on error.

ulong getSize(char[] name);
Get size of file name[].

Throws:
FileException on error.

void getTimes(char[] name, out d_time ftc, out d_time fta, out d_time ftm);
Get creation/access/modified times of file name[].

Throws:
FileException on error.

int exists(char[] name);
Does file name[] (or directory) exist? Return 1 if it does, 0 if not.

uint getAttributes(string name);
Get file name[] attributes.

Throws:
FileException on error.

int isfile(char[] name);
Is name[] a file?

Throws:
FileException if name[] doesn't exist.

int isdir(char[] name);
Is name[] a directory?

Throws:
FileException if name[] doesn't exist.

void chdir(char[] pathname);
Change directory to pathname[].

Throws:
FileException on error.

void mkdir(char[] pathname);
Make directory pathname[].

Throws:
FileException on error.

void rmdir(char[] pathname);
Remove directory pathname[].

Throws:
FileException on error.

char[] getcwd();
Get current directory.

Throws:
FileException on error.

struct DirEntry;
Directory Entry

string name;
file or directory name

ulong size;
size of file in bytes

d_time creationTime;
time of file creation

d_time lastAccessTime;
time file was last accessed

d_time lastWriteTime;
time file was last written to

uint isdir();
Return !=0 if DirEntry is a directory.

uint isfile();
Return !=0 if DirEntry is a file.

string[] listdir(string pathname);
Return contents of directory pathname[]. The names in the contents do not include the pathname.

Throws:
FileException on error

Example:
This program lists all the files and subdirectories in its path argument.
 import std.stdio;
 import std.file;

 void main(string[] args)
 {
    auto dirs = std.file.listdir(args[1]);

    foreach (d; dirs)
      writefln(d);
 }

string[] listdir(string pathname, string pattern);
string[] listdir(string pathname, RegExp r);
Return all the files in the directory and its subdirectories that match pattern or regular expression r.

Params:
string pathname | Directory name
string pattern | String with wildcards, such as "*.d". The supported wildcard strings are described under fnmatch() in std.path.
r | Regular expression, for more powerful pattern matching.

Example:
This program lists all the files with a "d" extension in the path passed as the first argument.
 import std.stdio;
 import std.file;

 void main(string[] args)
 {
    auto d_source_files = std.file.listdir(args[1], "*.d");

    foreach (d; d_source_files)
      writefln(d);
 }
A regular expression version that searches for all files with "d" or "obj" extensions:
 import std.stdio;
 import std.file;
 import std.regexp;

 void main(string[] args)
 {
    auto d_source_files = std.file.listdir(args[1], RegExp(r"\.(d|obj)$"));

    foreach (d; d_source_files)
      writefln(d);
 }

void listdir(string pathname, bool delegate(char[] filename) callback);
For each file and directory name in pathname[], pass it to the callback delegate.

Params:
bool delegate(char[] filename) callback Delegate that processes each filename in turn. Returns true to continue, false to stop.

Example:
This program lists all the files in its path argument, including the path.
 import std.stdio;
 import std.path;
 import std.file;

 void main(string[] args)
 {
    auto pathname = args[1];
    string[] result;

    bool listing(string filename)
    {
      result ~= std.path.join(pathname, filename);
      return true; // continue
    }

    listdir(pathname, &listing);

    foreach (name; result)
      writefln("%s", name);
 }

void listdir(string pathname, bool delegate(DirEntry* de) callback);
For each file and directory DirEntry in pathname[], pass it to the callback delegate.

Params:
bool delegate(DirEntry* de) callback Delegate that processes each DirEntry in turn. Returns true to continue, false to stop.

Example:
This program lists all the files in its path argument and all subdirectories thereof.
 import std.stdio;
 import std.file;

 void main(string[] args)
 {
    bool callback(DirEntry* de)
    {
      if (de.isdir)
        listdir(de.name, &callback);
      else
        writefln(de.name);
      return true;
    }

    listdir(args[1], &callback);
 }

char* toMBSz(string s);
Since Win 9x does not support the "W" API's, first convert to wchar, then convert to multibyte using the current code page. (Thanks to yaneurao for this)

Deprecated:
use std.windows.charset.toMBSz instead.

void copy(string from, string to);
Copy a file from[] to[].

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.format

This module implements the workhorse functionality for string and I/O formatting. It's comparable to C99's vsprintf().

Source:
std/format.d

class FormatError: object.Error;
Signals a mismatch between a format and its corresponding argument.

void doFormat(void delegate(dchar) putc, TypeInfo[] arguments, va_list argptr);
Interprets variadic argument list pointed to by argptr whose types are given by arguments[], formats them according to embedded format strings in the variadic argument list, and sends the resulting characters to putc.

The variadic arguments are consumed in order. Each is formatted into a sequence of chars, using the default format specification for its type, and the characters are sequentially passed to putc. If a char[], wchar[], or dchar[] argument is encountered, it is interpreted as a format string. As many arguments as specified in the format string are consumed and formatted according to the format specifications in that string and passed to putc. If there are too few remaining arguments, a FormatError is thrown. If there are more remaining arguments than needed by the format specification, the default processing of arguments resumes until they are all consumed.

Params:
void delegate(dchar) putc | Output is sent do this delegate, character by character.
TypeInfo[] arguments | Array of TypeInfo's, one for each argument to be formatted.
va_list argptr | Points to variadic argument list.

Throws:
Mismatched arguments and formats result in a FormatError being thrown.

Format String:
Format strings consist of characters interspersed with format specifications. Characters are simply copied to the output (such as putc) after any necessary conversion to the corresponding UTF-8 sequence.

A format specification starts with a '%' character, and has the following grammar:

FormatSpecification:
    '%%'
    '%' Flags Width Precision FormatChar

Flags:
    empty
    '-' Flags
    '+' Flags
    '#' Flags
    '0' Flags
    ' ' Flags

Width:
    empty
    Integer
    '*'

Precision:
    empty
    '.'
    '.' Integer
    '.*'

Integer:
    Digit
    Digit Integer

Digit:
    '0'
    '1'
    '2'
    '3'
    '4'
    '5'
    '6'
    '7'
    '8'
    '9'

FormatChar:
    's'
    'b'
    'd'
    'o'
    'x'
    'X'
    'e'
    'E'
    'f'
    'F'
    'g'
    'G'
    'a'
    'A'
Flags
'-'
Left justify the result in the field. It overrides any 0 flag.

'+'
Prefix positive numbers in a signed conversion with a +. It overrides any space flag.

'#'
Use alternative formatting:
For 'o':
Add to precision as necessary so that the first digit of the octal formatting is a '0', even if both the argument and the Precision are zero.
For 'x' ('X'):
If non-zero, prefix result with 0x (0X).
For floating point formatting:
Always insert the decimal point.
For 'g' ('G'):
Do not elide trailing zeros.

'0'
For integer and floating point formatting when not nan or infinity, use leading zeros to pad rather than spaces. Ignore if there's a Precision.

' '
Prefix positive numbers in a signed conversion with a space.

Width
Specifies the minimum field width. If the width is a *, the next argument, which must be of type int, is taken as the width. If the width is negative, it is as if the - was given as a Flags character.

Precision
Gives the precision for numeric conversions. If the precision is a *, the next argument, which must be of type int, is taken as the precision. If it is negative, it is as if there was no Precision.

FormatChar
's'
The corresponding argument is formatted in a manner consistent with its type:
bool
The result is 'true' or 'false'.
integral types
The %d format is used.
floating point types
The %g format is used.
string types
The result is the string converted to UTF-8. A Precision specifies the maximum number of characters to use in the result.
classes derived from Object
The result is the string returned from the class instance's .toString() method. A Precision specifies the maximum number of characters to use in the result.
non-string static and dynamic arrays
The result is [s0, s1, ...] where sk is the kth element formatted with the default format.

'b','d','o','x','X'
The corresponding argument must be an integral type and is formatted as an integer. If the argument is a signed type and the FormatChar is d it is converted to a signed string of characters, otherwise it is treated as unsigned. An argument of type bool is formatted as '1' or '0'. The base used is binary for b, octal for o, decimal for d, and hexadecimal for x or X. x formats using lower case letters, X uppercase. If there are fewer resulting digits than the Precision, leading zeros are used as necessary. If the Precision is 0 and the number is 0, no digits result.

'e','E'
A floating point number is formatted as one digit before the decimal point, Precision digits after, the FormatChar, ±, followed by at least a two digit exponent: d.dddddde±dd. If there is no Precision, six digits are generated after the decimal point. If the Precision is 0, no decimal point is generated.

'f','F'
A floating point number is formatted in decimal notation. The Precision specifies the number of digits generated after the decimal point. It defaults to six. At least one digit is generated before the decimal point. If the Precision is zero, no decimal point is generated.

'g','G'
A floating point number is formatted in either e or f format for g; E or F format for G. The f format is used if the exponent for an e format is greater than -5 and less than the Precision. The Precision specifies the number of significant digits, and defaults to six. Trailing zeros are elided after the decimal point, if the fractional part is zero then no decimal point is generated.

'a','A'
A floating point number is formatted in hexadecimal exponential notation 0xh.hhhhhhp±d. There is one hexadecimal digit before the decimal point, and as many after as specified by the Precision. If the Precision is zero, no decimal point is generated. If there is no Precision, as many hexadecimal digits as necessary to exactly represent the mantissa are generated. The exponent is written in as few digits as possible, but at least one, is in decimal, and represents a power of 2 as in h.hhhhhh*2±d. The exponent for zero is zero. The hexadecimal digits, x and p are in upper case if the FormatChar is upper case.

Floating point NaN's are formatted as nan if the FormatChar is lower case, or NAN if upper. Floating point infinities are formatted as inf or infinity if the FormatChar is lower case, or INF or INFINITY if upper.

Example:
import std.c.stdio;
import std.format;

void formattedPrint(...)
{
    void putc(char c)
    {
        fputc(c, stdout);
    }

    std.format.doFormat(&putc, _arguments, _argptr);
}

...

int x = 27;
// prints 'The answer is 27:6'
formattedPrint("The answer is %s:", x, 6);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.gc

The garbage collector normally works behind the scenes without needing any specific interaction. These functions are for advanced applications that benefit from tuning the operation of the collector.

Source:
std/gc.d

void addRoot(void* p);
Add p to list of roots. Roots are references to memory allocated by the collector that are maintained in memory outside the collector pool. The garbage collector will by default look for roots in the stacks of each thread, the registers, and the default static data segment. If roots are held elsewhere, use addRoot() or addRange() to tell the collector not to free the memory it points to.

void removeRoot(void* p);
Remove p from list of roots.

void addRange(void* pbot, void* ptop);
Add range to scan for roots.

void removeRange(void* pbot);
Remove range.

void hasPointers(void* p);
Mark a gc allocated block of memory as possibly containing pointers.

void hasNoPointers(void* p);
Mark a gc allocated block of memory as definitely NOT containing pointers.

void setTypeInfo(TypeInfo ti, void* p);
Mark a gc allocated block of memory pointed to by p as being populated with an array of TypeInfo ti (as many as will fit).

void[] malloc(size_t nbytes);
Allocate nbytes of uninitialized data. The allocated memory will be scanned for pointers during a gc collection cycle, unless it is followed by a call to hasNoPointers().

void[] realloc(void* p, size_t nbytes);
Resize allocated memory block pointed to by p to be at least nbytes long. It will try to resize the memory block in place. If nbytes is 0, the memory block is free'd. If p is null, the memory block is allocated using malloc. The returned array may not be at the same location as the original memory block. The allocated memory will be scanned for pointers during a gc collection cycle, unless it is followed by a call to hasNoPointers().

size_t extend(void* p, size_t minbytes, size_t maxbytes);
Attempt to enlarge the memory block pointed to by p by at least minbytes beyond its current capacity, up to a maximum of maxbytes.

Returns:
0 if could not extend p, total size of entire memory block if successful.

size_t capacity(void* p);
Returns capacity (size of the memory block) that p points to the beginning of. If p does not point into the gc memory pool, or does not point to the beginning of an allocated memory block, 0 is returned.

void setV1_0();
Set gc behavior to match that of 1.0.

void fullCollect();
Run a full garbage collection cycle.

The collector normally runs synchronously with a storage allocation request (i.e. it never happens when in code that does not allocate memory). In some circumstances, for example when a particular task is finished, it is convenient to explicitly run the collector and free up all memory used by that task. It can also be helpful to run a collection before starting a new task that would be annoying if it ran a collection in the middle of that task. Explicitly running a collection can also be done in a separate very low priority thread, so that if the program is idly waiting for input, memory can be cleaned up.

void genCollect();
Run a generational garbage collection cycle. Takes less time than a fullcollect(), but isn't as effective.

void minimize();
Minimizes physical memory usage

void disable();
void enable();
disable() temporarily disables garbage collection cycle, enable() then reenables them.

This is used for brief time critical sections of code, so the amount of time it will take is predictable. If the collector runs out of memory while it is disabled, it will throw an std.outofmemory.OutOfMemoryException. The disable() function calls can be nested, but must be matched with corresponding enable() calls. By default collections are enabled.

void* getGCHandle();
Get handle to the collector.

void setGCHandle(void* p);
Set handle to the collector.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.intrinsic

These functions are built-in intrinsics to the compiler.

Intrinsic functions are functions built in to the compiler, usually to take advantage of specific CPU features that are inefficient to handle via external functions. The compiler's optimizer and code generator are fully integrated in with intrinsic functions, bringing to bear their full power on them. This can result in some surprising speedups.

License:
Public Domain

Authors:
Walter Bright

Source:
std/intrinsic.d

int bsf(size_t v);
Scans the bits in v starting with bit 0, looking for the first set bit.

Returns:
The bit number of the first bit set. The return value is undefined if v is zero.

int bsr(size_t v);
Scans the bits in v from the most significant bit to the least significant bit, looking for the first set bit.

Returns:
The bit number of the first bit set. The return value is undefined if v is zero.

Example:
 import std.stdio;
 import std.intrinsic;

 int main()
 {
     uint v;
     int x;

     v = 0x21;
     x = bsf(v);
     writefln("bsf(x%x) = %d", v, x);
     x = bsr(v);
     writefln("bsr(x%x) = %d", v, x);
     return 0;
 }

Output:
bsf(x21) = 0
bsr(x21) = 5

int bt(uint* p, size_t bitnum);
Tests the bit.

int btc(uint* p, size_t bitnum);
Tests and complements the bit.

int btr(uint* p, size_t bitnum);
Tests and resets (sets to 0) the bit.

int bts(uint* p, size_t bitnum);
Tests and sets the bit.

Params:
uint* p a non-NULL pointer to an array of size_ts.
index a bit number, starting with bit 0 of p[0], and progressing. It addresses bits like the expression:
p[index / (size_t.sizeof*8)] & (1 << (index & ((size_t.sizeof*8) - 1)))

Returns:
A non-zero value if the bit was set, and a zero if it was clear.

Example:
import std.stdio;
import std.intrinsic;

int main()
{
    size_t array[2];

    array[0] = 2;
    array[1] = 0x100;

    writefln("btc(array, 35) = %d", <b>btc</b>(array, 35));
    writefln("array = [0]:x%x, [1]:x%x", array[0], array[1]);

    writefln("btc(array, 35) = %d", <b>btc</b>(array, 35));
    writefln("array = [0]:x%x, [1]:x%x", array[0], array[1]);

    writefln("bts(array, 35) = %d", <b>bts</b>(array, 35));
    writefln("array = [0]:x%x, [1]:x%x", array[0], array[1]);

    writefln("btr(array, 35) = %d", <b>btr</b>(array, 35));
    writefln("array = [0]:x%x, [1]:x%x", array[0], array[1]);

    writefln("bt(array, 1) = %d", <b>bt</b>(array, 1));
    writefln("array = [0]:x%x, [1]:x%x", array[0], array[1]);

    return 0;
}

Output:
btc(array, 35) = 0
array = [0]:x2, [1]:x108
btc(array, 35) = -1
array = [0]:x2, [1]:x100
bts(array, 35) = 0
array = [0]:x2, [1]:x108
btr(array, 35) = -1
array = [0]:x2, [1]:x100
bt(array, 1) = -1
array = [0]:x2, [1]:x100

uint bswap(uint v);
Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3 becomes byte 0.

ubyte inp(uint port_address);
ushort inpw(uint port_address);
uint inpl(uint port_address);
Reads I/O port at port_address.

ubyte outp(uint port_address, ubyte value);
ushort outpw(uint port_address, ushort value);
uint outpl(uint port_address, uint value);
Writes and returns value to I/O port at port_address.

Public Domain | Page generated by Ddoc.


std.math

Source:
std/math.d

const real E;
e

const real LOG2T;
log210

const real LOG2E;
log2e

const real LOG2;
log102

const real LOG10E;
log10e

const real LN2;
ln 2

const real LN10;
ln 10

const real PI;
π

const real PI_2;
π / 2

const real PI_4;
π / 4

const real M_1_PI;
1 / π

const real M_2_PI;
2 / π

const real M_2_SQRTPI;
2 / √π

const real SQRT2;
√2

const real SQRT1_2;
√½

real abs(real x);
long abs(long x);
int abs(int x);
real abs(creal z);
real abs(ireal y);
Calculates the absolute value

For complex numbers, abs(z) = sqrt( z.re2 + z.im2 ) = hypot(z.re, z.im).

creal conj(creal z);
ireal conj(ireal y);
Complex conjugate

conj(x + iy) = x - iy

Note that z * conj(z) = z.re2 - z.im2 is always a real number

real cos(real x);
Returns cosine of x. x is in radians.

Special Values
x | cos(x) | invalid?
NAN | NAN | yes
±∞ NAN yes

BUGS:
Results are undefined if |x| >= 264.

real sin(real x);
Returns sine of x. x is in radians.

Special Values
x | sin(x) | invalid?
NAN | NAN | yes
±0.0 | ±0.0 | no
±∞ NAN yes

BUGS:
Results are undefined if |x| >= 264.

creal sin(creal z);
ireal sin(ireal y);
sine, complex and imaginary

sin(z) = sin(z.re)*cosh(z.im) + cos(z.re)*sinh(z.im)i

If both sin(θ) and cos(θ) are required, it is most efficient to use expi(θ).

creal cos(creal z);
real cos(ireal y);
cosine, complex and imaginary

cos(z) = cos(z.re)*cosh(z.im) - sin(z.re)*sinh(z.im)i

real tan(real x);
Returns tangent of x. x is in radians.

Special Values
x | tan(x) | invalid?
NAN | NAN | yes
±0.0 | ±0.0 | no
±∞ NAN yes

real acos(real x);
Calculates the arc cosine of x, returning a value ranging from 0 to π.

Special Values
x | acos(x) | invalid?
>1.0 | NAN | yes
<-1.0 | NAN | yes
NAN | NAN | yes

real asin(real x);
Calculates the arc sine of x, returning a value ranging from -π/2 to π/2.

Special Values
x | asin(x) | invalid?
±0.0 | ±0.0 | no
>1.0 | NAN | yes
<-1.0 | NAN | yes

real atan(real x);
Calculates the arc tangent of x, returning a value ranging from -π/2 to π/2.

Special Values
x | atan(x) | invalid?
±0.0 | ±0.0 | no
±∞ NAN yes

real atan2(real y, real x);
Calculates the arc tangent of y / x, returning a value ranging from -π to π.

Special Values
y | x | atan(y, x)
NAN | anything | NAN
anything | NAN | NAN
±0.0 | >0.0 | ±0.0
±0.0 | +0.0 | ±0.0
±0.0 | <0.0 | ±π
±0.0 | -0.0 | ±π
>0.0 | ±0.0 | π/2
<0.0 | ±0.0 | -π/2
>0.0 ∞ ±0.0
±∞ anything ±π/2
>0.0 -∞ ±π
±∞ ∞ ±π/4
±∞ -∞ ±3π/4

real cosh(real x);
Calculates the hyperbolic cosine of x.

Special Values
x cosh(x) invalid?
±∞ ±0.0 no

real sinh(real x);
Calculates the hyperbolic sine of x.

Special Values
x | sinh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±∞ no

real tanh(real x);
Calculates the hyperbolic tangent of x.

Special Values
x | tanh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±1.0 no

real acosh(real x);
Calculates the inverse hyperbolic cosine of x.

Mathematically, acosh(x) = log(x + sqrt( x*x - 1))

Special Values
x | acosh(x)
NAN | NAN
<1 | NAN
1 | 0
+∞ +∞

real asinh(real x);
Calculates the inverse hyperbolic sine of x.

Mathematically,
  asinh(x) =  log( x + sqrt( x*x + 1 )) // if x >= +0
  asinh(x) = -log(-x + sqrt( x*x + 1 )) // if x <= -0

Special Values
x | asinh(x)
NAN | NAN
±0 | ±0
±∞ ±∞

real atanh(real x);
Calculates the inverse hyperbolic tangent of x, returning a value from ranging from -1 to 1.

Mathematically, atanh(x) = log( (1+x)/(1-x) ) / 2

Special Values
x | acosh(x)
NAN | NAN
±0 | ±0
-∞ -0

long rndtol(real x);
Returns x rounded to a long value using the current rounding mode. If the integer value of x is greater than long.max, the result is indeterminate.

real rndtonl(real x);
Returns x rounded to a long value using the FE_TONEAREST rounding mode. If the integer value of x is greater than long.max, the result is indeterminate.

float sqrt(float x);
double sqrt(double x);
real sqrt(real x);
Compute square root of x.

Special Values
x | sqrt(x) | invalid?
-0.0 | -0.0 | no
<0.0 | NAN | yes
+∞ +∞ no

real exp(real x);
Calculates ex.

Special Values
x | ex
+∞ +∞
-∞ +0.0
NAN | NAN

real expm1(real x);
Calculates the value of the natural logarithm base (e) raised to the power of x, minus 1.

For very small x, expm1(x) is more accurate than exp(x)-1.

Special Values
x | ex-1
±0.0 | ±0.0
+∞ +∞
-∞ -1.0
NAN | NAN

real exp2(real x);
Calculates 2x.

Special Values
x | exp2(x)
+∞ +∞
-∞ +0.0
NAN | NAN

creal expi(real y);
Calculate cos(y) + i sin(y).

On many CPUs (such as x86), this is a very efficient operation; almost twice as fast as calculating sin(y) and cos(y) separately, and is the preferred method when both are required.

real frexp(real value, out int exp);
Separate floating point value into significand and exponent.

Returns:
Calculate and return x and exp such that value =x*2exp and .5 <= |x| < 1.0

x has same sign as value.

Special Values
value | returns | exp
±0.0 | ±0.0 | 0
+∞ +∞ int.max
-∞ -∞ int.min
±NAN | ±NAN | int.min

int ilogb(real x);
Extracts the exponent of x as a signed integral value.

If x is not a special value, the result is the same as .

Special Values
x | ilogb(x) | Range error?
0 | FP_ILOGB0 | yes
±∞ int.max no
NAN | FP_ILOGBNAN | no

real ldexp(real n, int exp);
Compute n * 2exp

References:
frexp

real log(real x);
Calculate the natural logarithm of x.

Special Values
x | log(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

real log10(real x);
Calculate the base-10 logarithm of x.

Special Values
x | log10(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

real log1p(real x);
Calculates the natural logarithm of 1 + x.

For very small x, log1p(x) will be more accurate than log(1 + x).

Special Values
x | log1p(x) | divide by 0? | invalid?
±0.0 | ±0.0 | no | no
-1.0 -∞ yes no
<-1.0 | NAN | no | yes
+∞ -∞ no no

real log2(real x);
Calculates the base-2 logarithm of x: log2x

Special Values
x | log2(x) | divide by 0? | invalid?
±0.0 -∞ yes no
<0.0 | NAN | no | yes
+∞ +∞ no no

real logb(real x);
Extracts the exponent of x as a signed integral value.

If x is subnormal, it is treated as if it were normalized. For a positive, finite x:

1 <= x * FLT_RADIX-logb(x) < FLT_RADIX

Special Values
x logb(x) divide by 0?
±∞ +∞ no
±0.0 -∞ yes

real modf(real x, ref real i);
Calculates the remainder from the calculation x/y.

Returns:
The value of x - i * y, where i is the number of times that y can be completely subtracted from x. The result has the same sign as x.

Special Values
x | y | modf(x, y) | invalid?
±0.0 | not 0.0 | ±0.0 | no
±∞ anything NAN yes
anything | ±0.0 | NAN | yes
!=±∞ ±∞ x no

real scalbn(real x, int n);
Efficiently calculates x * 2n.

scalbn handles underflow and overflow in the same fashion as the basic arithmetic operators.

Special Values
x | scalb(x)
±∞ ±∞
±0.0 | ±0.0

real cbrt(real x);
Calculates the cube root of x.

Special Values
x | cbrt(x) | invalid?
±0.0 | ±0.0 | no
NAN | NAN | yes
±∞ ±∞ no

real fabs(real x);
Returns |x|

Special Values
x | fabs(x)
±0.0 | +0.0
±∞ +∞

real hypot(real x, real y);
Calculates the length of the hypotenuse of a right-angled triangle with sides of length x and y. The hypotenuse is the value of the square root of the sums of the squares of x and y:

sqrt( + )

Note that hypot(x, y), hypot(y, x) and hypot(x, -y) are equivalent.

Special Values
x y hypot(x, y) invalid?
x ±0.0 |x| no
±∞ y +∞ no
±∞ NAN +∞ no

real erf(real x);
Returns the error function of x.

error function

real erfc(real x);
Returns the complementary error function of x, which is 1 - erf(x).

complementary error function

real lgamma(real x);
Natural logarithm of gamma function.

Returns the base e (2.718...) logarithm of the absolute value of the gamma function of the argument.

For reals, lgamma is equivalent to log(fabs(gamma(x))).

Special Values
x | lgamma(x) | invalid?
NAN | NAN | yes
integer <= 0 +∞ yes
±∞ +∞ no

real tgamma(real x);
The Gamma function, Γ(x)

Γ(x) is a generalisation of the factorial function to real and complex numbers. Like x!, Γ(x+1) = x*Γ(x).

Mathematically, if z.re > 0 then Γ(z) = ∫0∞ tz-1e-t dt

Special Values
x | Γ(x) | invalid?
NAN | NAN | yes
±0.0 ±∞ yes
integer >0 | (x-1)! | no
integer <0 | NAN | yes
+∞ +∞ no
-∞ NAN yes

References:
http://en.wikipedia.org/wiki/Gamma_function, http://www.netlib.org/cephes/ldoubdoc.html#gamma

real ceil(real x);
Returns the value of x rounded upward to the next integer (toward positive infinity).

real floor(real x);
Returns the value of x rounded downward to the next integer (toward negative infinity).

real nearbyint(real x);
Rounds x to the nearest integer value, using the current rounding mode.

Unlike the rint functions, nearbyint does not raise the FE_INEXACT exception.

real rint(real x);
Rounds x to the nearest integer value, using the current rounding mode. If the return value is not equal to x, the FE_INEXACT exception is raised. nearbyint performs the same operation, but does not set the FE_INEXACT exception.

long lrint(real x);
Rounds x to the nearest integer value, using the current rounding mode.

This is generally the fastest method to convert a floating-point number to an integer. Note that the results from this function depend on the rounding mode, if the fractional part of x is exactly 0.5. If using the default rounding mode (ties round to even integers) lrint(4.5) == 4, lrint(5.5)==6.

real round(real x);
Return the value of x rounded to the nearest integer. If the fractional part of x is exactly 0.5, the return value is rounded to the even integer.

long lround(real x);
Return the value of x rounded to the nearest integer.

If the fractional part of x is exactly 0.5, the return value is rounded away from zero.

Note:
Not supported on windows

real trunc(real x);
Returns the integer portion of x, dropping the fractional portion.

This is also known as "chop" rounding.

real remainder(real x, real y);
real remquo(real x, real y, out int n);
Calculate the remainder x REM y, following IEC 60559.

REM is the value of x - y * n, where n is the integer nearest the exact value of x / y. If |n - x / y| == 0.5, n is even. If the result is zero, it has the same sign as x. Otherwise, the sign of the result is the sign of x / y. Precision mode has no effect on the remainder functions.

remquo returns n in the parameter n.

Special Values
x | y | remainder(x, y) | n | invalid?
±0.0 | not 0.0 | ±0.0 | 0.0 | no
±∞ anything NAN ? yes
anything ±0.0 NAN ? yes
!= ±∞ ±∞ x ? no

Note:
remquo not supported on windows

int isnan(real x);
Returns !=0 if e is a NaN.

int isfinite(real e);
Returns !=0 if e is finite (not infinite or NAN).

int isnormal(X)(X x);
Returns !=0 if x is normalized (not zero, subnormal, infinite, or NAN).

int issubnormal(float f);
int issubnormal(double d);
int issubnormal(real x);
Is number subnormal? (Also called "denormal".) Subnormals have a 0 exponent and a 0 most significant mantissa bit.

int isinf(real x);
Return !=0 if e is ±∞.

bool isIdentical(real x, real y);
Is the binary representation of x identical to y?

Same as ==, except that positive and negative zero are not identical, and two NANs are identical if they have the same 'payload'.

int signbit(real x);
Return 1 if sign bit of e is set, 0 if not.

real copysign(real to, real from);
Return a value composed of to with from's sign bit.

real nan(char[] tagp);
Creates a quiet NAN with the information from tagp[] embedded in it.

BUGS:
DMD always returns real.nan, ignoring the payload.

real nextUp(real x);
double nextUp(double x);
float nextUp(float x);
Calculate the next largest floating point value after x.

Return the least number greater than x that is representable as a real; thus, it gives the next point on the IEEE number line.

Special Values
x | nextUp(x)
-∞ -real.max
±0.0 | real.min*real.epsilon
real.max ∞
∞ ∞
NAN | NAN

Remarks:
This function is included in the forthcoming IEEE 754R standard.

real nextDown(real x);
double nextDown(double x);
float nextDown(float x);
Calculate the next smallest floating point value before x.

Return the greatest number less than x that is representable as a real; thus, it gives the previous point on the IEEE number line.

Special Values
x | nextDown(x)
∞ real.max
±0.0 | -real.min*real.epsilon
-real.max -∞
-∞ -∞
NAN | NAN

Remarks:
This function is included in the forthcoming IEEE 754R standard.

real nextafter(real x, real y);
float nextafter(float x, float y);
double nextafter(double x, double y);
Calculates the next representable value after x in the direction of y.

If y > x, the result will be the next largest floating-point value; if y < x, the result will be the next smallest value. If x == y, the result is y.

Remarks:
This function is not generally very useful; it's almost always better to use the faster functions nextUp() or nextDown() instead.

IEEE 754 requirements not implemented on Windows: The FE_INEXACT and FE_OVERFLOW exceptions will be raised if x is finite and the function result is infinite. The FE_INEXACT and FE_UNDERFLOW exceptions will be raised if the function value is subnormal, and x is not equal to y.

real fdim(real x, real y);
Returns the positive difference between x and y.

Returns:
Special Values
x, y | fdim(x, y)
x > y | x - y
x <= y | +0.0

real fmax(real x, real y);
Returns the larger of x and y.

real fmin(real x, real y);
Returns the smaller of x and y.

real fma(real x, real y, real z);
Returns (x * y) + z, rounding only once according to the current rounding mode.

BUGS:
Not currently implemented - rounds twice.

real pow(real x, uint n);
real pow(real x, int n);
Fast integral powers.

real pow(real x, real y);
Calculates x y.

Special Values
x | y | pow(x, y) | div 0 | invalid?
anything | ±0.0 | 1.0 | no | no
|x| > 1 +∞ +∞ no no
|x| < 1 +∞ +0.0 no no
|x| > 1 -∞ +0.0 no no
|x| < 1 -∞ +∞ no no
+∞ > 0.0 +∞ no no
+∞ < 0.0 +0.0 no no
-∞ odd integer > 0.0 -∞ no no
-∞ > 0.0, not odd integer +∞ no no
-∞ odd integer < 0.0 -0.0 no no
-∞ < 0.0, not odd integer +0.0 no no
±1.0 ±∞ NAN no yes
< 0.0 | finite, nonintegral | NAN | no | yes
±0.0 odd integer < 0.0 ±∞ yes no
±0.0 < 0.0, not odd integer +∞ yes no
±0.0 | odd integer > 0.0 | ±0.0 | no | no
±0.0 | > 0.0, not odd integer | +0.0 | no | no

int feqrel(X)(X x, X y);
To what precision is x equal to y?

Returns:
the number of mantissa bits which are equal in x and y. eg, 0x1.F8p+60 and 0x1.F1p+60 are equal to 5 bits of precision.

Special Values
x | y | feqrel(x, y)
x | x | real.mant_dig
x | >= 2*x | 0
x | <= x/2 | 0
NAN | any | 0
any | NAN | 0

real poly(real x, real[] A);
Evaluate polynomial A(x) = a0 + a1x + a2² + a3x³ ...

Uses Horner's rule A(x) = a0 + x(a1 + x(a2 + x(a3 + ...)))

Params:
real[] A array of coefficients a0, a1, etc.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.md5

Computes MD5 digests of arbitrary data. MD5 digests are 16 byte quantities that are like a checksum or crc, but are more robust.

There are two ways to do this. The first does it all in one function call to sum(). The second is for when the data is buffered.

BUGS:
MD5 digests have been demonstrated to not be unique.

Author:
The routines and algorithms are derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.

References:
Wikipedia on MD5

Source:
std/md5.d

Example:
// This code is derived from the
// RSA Data Security, Inc. MD5 Message-Digest Algorithm.

import std.md5;

private import std.stdio;
private import std.string;
private import std.c.stdio;
private import std.c.string;

int main(char[][] args)
{
    foreach (char[] arg; args)
         MDFile(arg);
    return 0;
}

/* Digests a file and prints the result. */
void MDFile(char[] filename)
{
    FILE* file;
    MD5_CTX context;
    int len;
    ubyte[4 * 1024] buffer;
    ubyte digest[16];

    if ((file = fopen(std.string.toStringz(filename), "rb")) == null)
        writefln("%s can't be opened", filename);
    else
    {
        context.start();
        while ((len = fread(buffer, 1, buffer.sizeof, file)) != 0)
            context.update(buffer[0 .. len]);
        context.finish(digest);
        fclose(file);

        writefln("MD5 (%s) = %s", filename, digestToString(digest));
    }
}

void sum(ubyte[16u] digest, void[] data);
Computes MD5 digest of array of data.

void printDigest(ubyte[16u] digest);
Prints a message digest in hexadecimal to stdout.

char[] digestToString(ubyte[16u] digest);
Converts MD5 digest to a string.

struct MD5_CTX;
Holds context of MD5 computation.

Used when data to be digested is buffered.

void start();
MD5 initialization. Begins an MD5 operation, writing a new context.

void update(void[] input);
MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context.

void finish(ubyte[16u] digest);
MD5 finalization. Ends an MD5 message-digest operation, writing the the message to digest and zeroing the context.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.metastrings

Templates with which to do compile time manipulation of strings.

Source:
std/metastrings.d

template Format(A...)
Formats constants into a string at compile time. Analogous to std.string.format().

Parameters:
A = tuple of constants, which can be strings, characters, or integral values.

Formats:
The formats supported are %s for strings, and %% for the % character.

Example:
import std.metastrings;
import std.stdio;

void main()
{
  string s = Format!("Arg %s = %s", "foo", 27);
  writefln(s); // "Arg foo = 27"
}

template ToString(ulong U)
template ToString(long I)
template ToString(uint U)
template ToString(int I)
template ToString(ushort U)
template ToString(short I)
template ToString(ubyte U)
template ToString(byte I)
template ToString(bool B)
template ToString(string S)
template ToString(char C)
Convert constant argument to a string.

template ParseUinteger(string s)
Parse unsigned integer literal from the start of string s.

Returns:
.value = the integer literal as a string, .rest = the string following the integer literal

Otherwise:
.value = null, .rest = s

template ParseInteger(string s)
Parse integer literal optionally preceded by '-' from the start of string s.

Returns:
.value = the integer literal as a string, .rest = the string following the integer literal

Otherwise:
.value = null, .rest = s

Public Domain | Page generated by Ddoc.


std.mmfile

Read and write memory mapped files.

Source:
std/mmfile.d

class MmFile;
MmFile objects control the memory mapped file resource.

enum Mode;
The mode the memory mapped file is opened with.

Read
read existing file

ReadWriteNew
delete existing file, write new file

ReadWrite
read/write existing file, create if not existing

ReadCopyOnWrite
read/write existing file, copy on write

this(string filename);
Open memory mapped file filename for reading. File is closed when the object instance is deleted.

Throws:
std.file.FileException

this(string filename, Mode mode, ulong size, void* address, size_t window = 0);
Open memory mapped file filename in mode. File is closed when the object instance is deleted.

Params:
string filename | name of the file. If null, an anonymous file mapping is created.
Mode mode | access mode defined above.
ulong size | the size of the file. If 0, it is taken to be the size of the existing file.
void* address | the preferred address to map the file to, although the system is not required to honor it. If null, the system selects the most convenient address.
size_t window | preferred block size of the amount of data to map at one time with 0 meaning map the entire file. The window size must be a multiple of the memory allocation page size.

Throws:
std.file.FileException

ulong length();
Gives size in bytes of the memory mapped file.

Mode mode();
Read-only property returning the file mode.

void[] opSlice();
Returns entire file contents as an array.

void[] opSlice(ulong i1, ulong i2);
Returns slice of file contents as an array.

ubyte opIndex(ulong i);
Returns byte at index i in file.

ubyte opIndexAssign(ubyte value, ulong i);
Sets and returns byte at index i in file to value.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.openrj

Open-RJ mapping for the D standard library.

Authors:
Matthew Wilson

References:
Open-RJ

Source:
std/openrj.d

enum ORJ_FLAG;
Flags that moderate the creation of Databases

ORDER_FIELDS
Arranges the fields in alphabetical order

ELIDE_BLANK_RECORDS
Causes blank records to be ignored

char[] toString(ORJ_FLAG f);

enum ORJRC;
General error codes

SUCCESS
Operation was successful

CANNOT_OPEN_JAR_FILE
The given file does not exist, or cannot be accessed

NO_RECORDS
The database file contained no records

OUT_OF_MEMORY
The API suffered memory exhaustion

BAD_FILE_READ
A read operation failed

PARSE_ERROR
Parsing of the database file failed due to a syntax error

INVALID_INDEX
An invalid index was specified

UNEXPECTED
An unexpected condition was encountered

INVALID_CONTENT
The database file contained invalid content

char[] toString(ORJRC f);

enum ORJ_PARSE_ERROR;
Parsing error codes

SUCCESS
Parsing was successful

RECORD_SEPARATOR_IN_CONTINUATION
A record separator was encountered during a content line continuation

UNFINISHED_LINE
The last line in the database was not terminated by a line-feed

UNFINISHED_FIELD
The last field in the database file was not terminated by a record separator

UNFINISHED_RECORD
The last record in the database file was not terminated by a record separator

char[] toString(ORJ_PARSE_ERROR f);

class OpenRJException: object.Exception;

class DatabaseException: std.openrj.OpenRJException;

ORJRC rc();

ORJ_PARSE_ERROR parseError();

int lineNum();

class InvalidKeyException: std.openrj.OpenRJException;

class InvalidTypeException: std.openrj.OpenRJException;

class Field;
Represents a field in the database

final char[] name();

final char[] value();

Record record();

class Record;
Represents a record in the database, consisting of a set of fields

size_t numFields();

size_t length();

Field[] fields();

Field opIndex(index_type index);

char[] opIndex(char[] fieldName);

Field getField(char[] fieldName);

Field findField(char[] fieldName);

int hasField(char[] fieldName);

Database database();

int opApply(int delegate(ref Field field) dg);

int opApply(int delegate(char[] name, char[] value) dg);

class Database;

this(char[] memory, uint flags);

this(char[][] lines, uint flags);

size_type numRecords();

size_type numFields();

size_type numLines();

uint flags();

Record[] records();

Field[] fields();

size_t length();

Record opIndex(index_type index);

Record[] getRecordsContainingField(char[] fieldName);

Record[] getRecordsContainingField(char[] fieldName, char[] fieldValue);

int opApply(int delegate(ref Record record) dg);

int opApply(int delegate(ref Field field) dg);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.outbuffer

Boilerplate:

Source:
std/outbuffer.d

class OutBuffer;
OutBuffer provides a way to build up an array of bytes out of raw data. It is useful for things like preparing an array of bytes to write out to a file. OutBuffer's byte order is the format native to the computer. To control the byte order (endianness), use a class derived from OutBuffer.

ubyte[] toBytes();
Convert to array of bytes.

void reserve(size_t nbytes);
Preallocate nbytes more to the size of the internal buffer.

This is a speed optimization, a good guess at the maximum size of the resulting buffer will improve performance by eliminating reallocations and copying.

void write(ubyte[] bytes);
void write(ubyte b);
void write(byte b);
void write(char c);
void write(ushort w);
void write(short s);
void write(wchar c);
void write(uint w);
void write(int i);
void write(ulong l);
void write(long l);
void write(float f);
void write(double f);
void write(real f);
void write(string s);
void write(OutBuffer buf);
Append data to the internal buffer.

void fill0(size_t nbytes);
Append nbytes of 0 to the internal buffer.

void alignSize(size_t alignsize);
0-fill to align on power of 2 boundary.

void align2();
Optimize common special case alignSize(2)

void align4();
Optimize common special case alignSize(4)

string toString();
Convert internal buffer to array of chars.

void vprintf(string format, va_list args);
Append output of C's vprintf() to internal buffer.

void printf(string format, ...);
Append output of C's printf() to internal buffer.

void spread(size_t index, size_t nbytes);
At offset index into buffer, create nbytes of space by shifting upwards all data past index.

Copyright (c) 2001-2005 by Digital Mars All Rights Reserved www.digitalmars.com | Page generated by Ddoc.


std.outofmemory

Source:
std/outofmemory.d

class OutOfMemoryException: object.Exception;
This exception is thrown when out of memory errors happen.

this();
Default constructor

Placed into public domain. www.digitalmars.com | Page generated by Ddoc.


std.path

Source:
std/path.d

http:
//www.digitalmars.com

Grzegorz Adam Hankiewicz added some documentation.

This module is used to parse file names. All the operations work only on strings; they don't perform any input/output operations. This means that if a path contains a directory name with a dot, functions like getExt() will work with it just as if it was a file. To differentiate these cases, use the std.file module first (i.e. std.file.isDir()).

const char[1u] sep;
String used to separate directory names in a path. Under Windows this is a backslash, under Linux a slash.

const char[1u] altsep;
Alternate version of sep[] used in Windows (a slash). Under Linux this is empty.

const char[1u] pathsep;
Path separator string. A semi colon under Windows, a colon under Linux.

const char[2u] linesep;
String used to separate lines. String used to separate lines, \r\n under Windows and \n under Linux.

const char[1u] curdir;
String representing the current directory.

const char[2u] pardir;
String representing the parent directory.

alias fcmp;
Compare file names.

Returns:
< 0 | filename1 < filename2
= 0 | filename1 == filename2
> 0 | filename1 > filename2

string getExt(string fullname);
Extracts the extension from a filename or path.

This function will search fullname from the end until the first dot, path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a dot was found, characters to its right are returned. If a path separator was found, or fullname didn't contain any dots or path separators, returns null.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getExt(r"d:\path\foo.bat") // "bat"
     getExt(r"d:\path.two\bar") // null
 }
 version(Posix)
 {
     getExt(r"/home/user.name/bar.")  // ""
     getExt(r"d:\path.two\bar")     // "two\\bar"
     getExt(r"/home/user/.resource")  // "resource"
 }

string getName(string fullname);
Returns the extensionless version of a filename or path.

This function will search fullname from the end until the first dot, path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a dot was found, characters to its left are returned. If a path separator was found, or fullname didn't contain any dots or path separators, returns null.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getName(r"d:\path\foo.bat") => "d:\path\foo"
     getName(r"d:\path.two\bar") => null
 }
 version(Posix)
 {
     getName("/home/user.name/bar.")  => "/home/user.name/bar"
     getName(r"d:\path.two\bar") => r"d:\path"
     getName("/home/user/.resource") => "/home/user/"
 }

string getBaseName(string fullname);
Extracts the base name of a path.

This function will search fullname from the end until the first path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a path separator was found, all the characters to its right are returned. Otherwise, fullname is returned.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getBaseName(r"d:\path\foo.bat") => "foo.bat"
 }
 version(Posix)
 {
     getBaseName("/home/user.name/bar.")  => "bar."
 }

string getDirName(string fullname);
Extracts the directory part of a path.

This function will search fullname from the end until the first path separator or first character of fullname is reached. Under Windows, the drive letter separator (colon) also terminates the search.

Returns:
If a path separator was found, all the characters to its left are returned. Otherwise, fullname is returned.

Under Windows, the found path separator will be included in the returned string if it is preceeded by a colon.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     getDirName(r"d:\path\foo.bat") => r"d:\path"
     getDirName(getDirName(r"d:\path\foo.bat")) => r"d:\"
 }
 version(Posix)
 {
     getDirName("/home/user")  => "/home"
     getDirName(getDirName("/home/user"))  => ""
 }

string getDrive(string fullname);
Extracts the drive letter of a path.

This function will search fullname for a colon from the beginning.

Returns:
If a colon is found, all the characters to its left plus the colon are returned. Otherwise, null is returned.

Under Linux, this function always returns null immediately.

Throws:
Nothing.

Examples:
 getDrive(r"d:\path\foo.bat") => "d:"

string defaultExt(string filename, string ext);
Appends a default extension to a filename.

This function first searches filename for an extension and appends ext if there is none. ext should not have any leading dots, one will be inserted between filename and ext if filename doesn't already end with one.

Returns:
filename if it contains an extension, otherwise filename + ext.

Throws:
Nothing.

Examples:
 defaultExt("foo.txt", "raw") => "foo.txt"
 defaultExt("foo.", "raw") => "foo.raw"
 defaultExt("bar", "raw") => "bar.raw"

string addExt(string filename, string ext);
Adds or replaces an extension to a filename.

This function first searches filename for an extension and replaces it with ext if found. If there is no extension, ext will be appended. ext should not have any leading dots, one will be inserted between filename and ext if filename doesn't already end with one.

Returns:
filename + ext if filename is extensionless. Otherwise strips filename's extension off, appends ext and returns the result.

Throws:
Nothing.

Examples:
 addExt("foo.txt", "raw") => "foo.raw"
 addExt("foo.", "raw") => "foo.raw"
 addExt("bar", "raw") => "bar.raw"

int isabs(string path);
Checks if path is absolute.

Returns:
non-zero if the path starts from the root directory (Linux) or drive letter and root directory (Windows), zero otherwise.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     isabs(r"relative\path") => 0
     isabs(r"\relative\path") => 0
     isabs(r"d:\absolute") => 1
 }
 version(Posix)
 {
     isabs("/home/user") => 1
     isabs("foo") => 0
 }

string join(string p1, string p2);
Joins two path components.

If p1 doesn't have a trailing path separator, one will be appended to it before concatting p2.

Returns:
p1 ~ p2. However, if p2 is an absolute path, only p2 will be returned.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     join(r"c:\foo", "bar") => r"c:\foo\bar"
     join("foo", r"d:\bar") => r"d:\bar"
 }
 version(Posix)
 {
     join("/foo/", "bar") => "/foo/bar"
     join("/foo", "/bar") => "/bar"
 }

int fncharmatch(dchar c1, dchar c2);
Matches filename characters.

Under Windows, the comparison is done ignoring case. Under Linux an exact match is performed.

Returns:
non zero if c1 matches c2, zero otherwise.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     fncharmatch('a', 'b') => 0
     fncharmatch('A', 'a') => 1
 }
 version(Posix)
 {
     fncharmatch('a', 'b') => 0
     fncharmatch('A', 'a') => 0
 }

int fnmatch(string filename, string pattern);
Matches a pattern against a filename.

Some characters of pattern have special a meaning (they are meta-characters) and can't be escaped. These are:

* Matches 0 or more instances of any character.
? Matches exactly one instances of any character.
[chars] | Matches one instance of any character that appears between the brackets.
[!chars] | Matches one instance of any character that does not appear between the brackets after the exclamation mark.

Internally individual character comparisons are done calling fncharmatch(), so its rules apply here too. Note that path separators and dots don't stop a meta-character from matching further portions of the filename.

Returns:
non zero if pattern matches filename, zero otherwise.

See Also:
fncharmatch().

Throws:
Nothing.

Examples:

 version(Windows)
 {
     fnmatch("foo.bar", "*") => 1
     fnmatch(r"foo/foo\bar", "f*b*r") => 1
     fnmatch("foo.bar", "f?bar") => 0
     fnmatch("Goo.bar", "[fg]???bar") => 1
     fnmatch(r"d:\foo\bar", "d*foo?bar") => 1
 }
 version(Posix)
 {
     fnmatch("Go*.bar", "[fg]???bar") => 0
     fnmatch("/foo*home/bar", "?foo*bar") => 1
     fnmatch("foobar", "foo?bar") => 1
 }

string expandTilde(string inputPath);
Performs tilde expansion in paths.

There are two ways of using tilde expansion in a path. One involves using the tilde alone or followed by a path separator. In this case, the tilde will be expanded with the value of the environment variable HOME. The second way is putting a username after the tilde (i.e. ~john/Mail). Here, the username will be searched for in the user database (i.e. /etc/passwd on Unix systems) and will expand to whatever path is stored there. The username is considered the string after the tilde ending at the first instance of a path separator.

Note that using the ~user syntax may give different values from just ~ if the environment variable doesn't match the value stored in the user database.

When the environment variable version is used, the path won't be modified if the environment variable doesn't exist or it is empty. When the database version is used, the path won't be modified if the user doesn't exist in the database or there is not enough memory to perform the query.

Returns:
inputPath with the tilde expanded, or just inputPath if it could not be expanded. For Windows, expandTilde() merely returns its argument inputPath.

Throws:
std.outofmemory.OutOfMemoryException if there is not enough memory to perform the database lookup for the ~user syntax.

Examples:
 import std.path;

 void process_file(string filename)
 {
     string path = expandTilde(filename);
     ...
 }

 import std.path;

 const string RESOURCE_DIR_TEMPLATE = "~/.applicationrc";
 string RESOURCE_DIR;    // This gets expanded in main().

 int main(string[] args)
 {
     RESOURCE_DIR = expandTilde(RESOURCE_DIR_TEMPLATE);
     ...
 }

Version:
Available since v0.143.

Authors:
Grzegorz Adam Hankiewicz, Thomas Kühne.

Placed into public domain. | Page generated by Ddoc.


std.process

Source:
std/process.d

int system(string command);
Execute command in a command shell.

Returns:
exit status of command

int execv(string pathname, string[] argv);
int execve(string pathname, string[] argv, string[] envp);
int execvp(string pathname, string[] argv);
int execvpe(string pathname, string[] argv, string[] envp);
Execute program specified by pathname, passing it the arguments (argv) and the environment (envp), returning the exit status. The 'p' versions of exec search the PATH environment variable setting for the program.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.random

Source:
std/random.d

void rand_seed(uint seed, uint index);
The random number generator is seeded at program startup with a random value. This ensures that each program generates a different sequence of random numbers. To generate a repeatable sequence, use rand_seed() to start the sequence. seed and index start it, and each successive value increments index. This means that the nth random number of the sequence can be directly generated by passing index + n to rand_seed().

Note:
This is more random, but slower, than C's rand() function. To use C's rand() instead, import std.c.stdlib.

uint rand();
Get the next random number in sequence.

BUGS:
shares a global single state, not multithreaded

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.regexp

Regular expressions are a powerful method of string pattern matching. The regular expression language used is the same as that commonly used, however, some of the very advanced forms may behave slightly differently.

std.regexp is designed to work only with valid UTF strings as input. To validate untrusted input, use std.utf.validate().

In the following guide, pattern[] refers to a regular expression. The attributes[] refers to a string controlling the interpretation of the regular expression. It consists of a sequence of one or more of the following characters:

Attribute Characters
Attribute | Action
g | global; repeat over the whole input string
i | case insensitive
m | treat as multiple lines separated by newlines

The format[] string has the formatting characters:

Formatting Characters
Format | Replaced With
$$ | $
$& | The matched substring.
$` | The portion of string that precedes the matched substring.
$' | The portion of string that follows the matched substring.
$n | The nth capture, where n is a single digit 1-9 and n is not followed by a decimal digit.
$nn | The nnth capture, where nn is a two-digit decimal number 01-99. If nnth capture is undefined or more than the number of parenthesized subexpressions, use the empty string instead.

Any other $ are left as is.

References:
Wikipedia

Source:
std/regexp.d

const char[] email;
Regular expression to extract an email address

const char[] url;
Regular expression to extract a url

class RegExpException: object.Exception;
One of these gets thrown on compilation errors

char[] sub(char[] string, char[] pattern, char[] format, char[] attributes = null);
Search string for matches with regular expression pattern with attributes. Replace each match with string generated from format.

Params:
char[] string | String to search.
char[] pattern | Regular expression pattern.
char[] format | Replacement string format.
char[] attributes | Regular expression attributes.

Returns:
the resulting string

Example:
Replace the letters 'a' with the letters 'ZZ'.
 s = "Strap a rocket engine on a chicken."
 sub(s, "a", "ZZ")        // result: StrZZp a rocket engine on a chicken.
 sub(s, "a", "ZZ", "g")   // result: StrZZp ZZ rocket engine on ZZ chicken.
The replacement format can reference the matches using the $&, $$, $', $`, .. 9 notation:
 sub(s, "[ar]", "[$&]", "g") // result: St[r][a]p [a] [r]ocket engine on [a] chi

char[] sub(char[] string, char[] pattern, char[] delegate(RegExp) dg, char[] attributes = null);
Search string for matches with regular expression pattern with attributes. Pass each match to delegate dg. Replace each match with the return value from dg.

Params:
char[] string | String to search.
char[] pattern | Regular expression pattern.
char[] delegate(RegExp) dg | Delegate
char[] attributes | Regular expression attributes.

Returns:
the resulting string.

Example:
Capitalize the letters 'a' and 'r':
 s = "Strap a rocket engine on a chicken.";
 sub(s, "[ar]",
    delegate char[] (RegExp m)
    {
         return toupper(m.match(0));
    },
    "g");    // result: StRAp A Rocket engine on A chicken.

ptrdiff_t find(rchar[] string, char[] pattern, char[] attributes = null);
Search string[] for first match with pattern[] with attributes[].

Params:
rchar[] string | String to search.
char[] pattern | Regular expression pattern.
char[] attributes | Regular expression attributes.

Returns:
index into string[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 std.regexp.find(s, "b");    // match, returns 1
 std.regexp.find(s, "f");    // no match, returns -1

ptrdiff_t rfind(rchar[] string, char[] pattern, char[] attributes = null);
Search string[] for last match with pattern[] with attributes[].

Params:
rchar[] string | String to search.
char[] pattern | Regular expression pattern.
char[] attributes | Regular expression attributes.

Returns:
index into string[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 std.regexp.find(s, "b");    // match, returns 9
 std.regexp.find(s, "f");    // no match, returns -1

char[][] split(char[] string, char[] pattern, char[] attributes = null);
Split string[] into an array of strings, using the regular expression pattern[] with attributes[] as the separator.

Params:
char[] string | String to search.
char[] pattern | Regular expression pattern.
char[] attributes | Regular expression attributes.

Returns:
array of slices into string[]

Example:
 foreach (s; split("abcabcabab", "C.", "i"))
 {
     writefln("s = '%s'", s);
 }
 // Prints:
 // s = 'ab'
 // s = 'b'
 // s = 'bab'

RegExp search(char[] string, char[] pattern, char[] attributes = null);
Search string[] for first match with pattern[] with attributes[].

Params:
char[] string | String to search.
char[] pattern | Regular expression pattern.
char[] attributes | Regular expression attributes.

Returns:
corresponding RegExp if found, null if not.

Example:
 import std.stdio;
 import std.regexp;

 void main()
 {
     if (auto m = std.regexp.search("abcdef", "c"))
     {
         writefln("%s[%s]%s", m.pre, m.match(0), m.post);
     }
 }
 // Prints:
 // ab[c]def

class RegExp;
RegExp is a class to handle regular expressions.

It is the core foundation for adding powerful string pattern matching capabilities to programs like grep, text editors, awk, sed, etc.

this(rchar[] pattern, rchar[] attributes = null);
Construct a RegExp object. Compile pattern with attributes into an internal form for fast execution.

Params:
rchar[] pattern | regular expression
rchar[] attributes | attributes

Throws:
RegExpException if there are any compilation errors.

Example:
Declare two variables and assign to them a RegExp object:
 auto r = new RegExp("pattern");
 auto s = new RegExp(r"p[1-5]\s*");

static RegExp opCall(rchar[] pattern, rchar[] attributes = null);
Generate instance of RegExp.

Params:
rchar[] pattern | regular expression
rchar[] attributes | attributes

Throws:
RegExpException if there are any compilation errors.

Example:
Declare two variables and assign to them a RegExp object:
 auto r = RegExp("pattern");
 auto s = RegExp(r"p[1-5]\s*");

RegExp search(rchar[] string);
int opApply(int delegate(ref RegExp) dg);
Set up for start of foreach loop.

Returns:
search() returns instance of RegExp set up to search string[].

Example:
 import std.stdio;
 import std.regexp;

 void main()
 {
     foreach(m; RegExp("ab").search("abcabcabab"))
     {
         writefln("%s[%s]%s", m.pre, m.match(0), m.post);
     }
 }
 // Prints:
 // [ab]cabcabab
 // abc[ab]cabab
 // abcabc[ab]ab
 // abcabcab[ab]

char[] match(size_t n);
Retrieve match n.

n==0 means the matched substring, n>0 means the n'th parenthesized subexpression. if n is larger than the number of parenthesized subexpressions, null is returned.

char[] pre();
Return the slice of the input that precedes the matched substring.

char[] post();
Return the slice of the input that follows the matched substring.

rchar[][] split(rchar[] string);
Split string[] into an array of strings, using the regular expression as the separator.

Returns:
array of slices into string[]

ptrdiff_t find(rchar[] string);
Search string[] for match with regular expression.

Returns:
index of match if successful, -1 if not found

rchar[][] match(rchar[] string);
Search string[] for match.

Returns:
If global attribute, return same value as exec(string). If not global attribute, return array of all matches.

rchar[] replace(rchar[] string, rchar[] format);
Find regular expression matches in string[]. Replace those matches with a new string composed of format[] merged with the result of the matches. If global, replace all matches. Otherwise, replace first match.

Returns:
the new string

rchar[][] exec(rchar[] string);
Search string[] for match.

Returns:
array of slices into string[] representing matches

rchar[][] exec();
Pick up where last exec(string) or exec() left off, searching string[] for next match.

Returns:
array of slices into string[] representing matches

int test(rchar[] string);
Search string[] for match.

Returns:
0 for no match, !=0 for match

Example:
import std.stdio;
import std.regexp;
import std.string;

int grep(int delegate(char[]) pred, char[][] list)
{
  int count;
  foreach (s; list)
  {  if (pred(s))
       ++count;
  }
  return count;
}

void main()
{
  auto x = grep(&RegExp("[Ff]oo").test,
                std.string.split("mary had a foo lamb"));
  writefln(x);
}
which prints: 1

int test();
Pick up where last test(string) or test() left off, and search again.

Returns:
0 for no match, !=0 for match

int test(char[] string, ptrdiff_t startindex);
Test string[] starting at startindex against regular expression.

Returns:
0 for no match, !=0 for match

rchar[] replace(rchar[] format);
After a match is found with test(), this function will take the match results and, using the format string, generate and return a new string.

rchar[] replaceOld(rchar[] format);
Like replace(char[] format), but uses old style formatting:
Format | Description
& replace with the match
\n | replace with the nth parenthesized match, n is 1..9
\c | replace with char c.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.signals

Signals and Slots are an implementation of the Observer Pattern. Essentially, when a Signal is emitted, a list of connected Observers (called slots) are called.

There have been several D implementations of Signals and Slots. This version makes use of several new features in D, which make using it simpler and less error prone. In particular, it is no longer necessary to instrument the slots.

References:
A Deeper Look at Signals and Slots
Observer pattern
Wikipedia
Boost Signals
Qt

There has been a great deal of discussion in the D newsgroups over this, and several implementations:

signal slots library
Signals and Slots in D
Dynamic binding -- Qt's Signals and Slots vs Objective-C
Dissecting the SS
about harmonia
Another event handling module
Suggestion: signal/slot mechanism
Signals and slots?
Signals and slots ready for evaluation
Signals & Slots for Walter
Signal/Slot mechanism?
Modern Features?
Delegates vs interfaces
The importance of component programming (properties, signals and slots, etc)
signals and slots

BUGS:
Slots can only be delegates formed from class objects or interfaces to class objects. If a delegate to something else is passed to connect(), such as a struct member function, a nested function or a COM interface, undefined behavior will result.

Not safe for multiple threads operating on the same signals or slots.

Source:
std/signals.d

Author:
Walter Bright, Digital Mars, www.digitalmars.com

template Signal(T1...)
Mixin to create a signal within a class object.

Different signals can be added to a class by naming the mixins.

Example:
import std.signals;
import std.stdio;

class Observer
{   // our slot
    void watch(char[] msg, int i)
    {
        writefln("Observed msg '%s' and value %s", msg, i);
    }
}

class Foo
{
    int value() { return _value; }

    int value(int v)
    {
        if (v != _value)
        {   _value = v;
            // call all the connected slots with the two parameters
            emit("setting new value", v);
        }
        return v;
    }

    // Mix in all the code we need to make Foo into a signal
    mixin Signal!(char[], int);

  private :
    int _value;
}

void main()
{
    Foo a = new Foo;
    Observer o = new Observer;

    a.value = 3;                // should not call o.watch()
    a.connect(&o.watch);        // o.watch is the slot
    a.value = 4;                // should call o.watch()
    a.disconnect(&o.watch);     // o.watch is no longer a slot
    a.value = 5;                // so should not call o.watch()
    a.connect(&o.watch);        // connect again
    a.value = 6;                // should call o.watch()
    delete o;                   // destroying o should automatically disconnect it
    a.value = 7;                // should not call o.watch()
}
which should print:
 Observed msg 'setting new value' and value 4
 Observed msg 'setting new value' and value 6

alias slot_t;
A slot is implemented as a delegate. The slot_t is the type of the delegate. The delegate must be to an instance of a class or an interface to a class instance. Delegates to struct instances or nested functions must not be used as slots.

void emit(T1 i);
Call each of the connected slots, passing the argument(s) i to them.

void connect(slot_t slot);
Add a slot to the list of slots to be called when emit() is called.

void disconnect(slot_t slot);
Remove a slot from the list of slots to be called when emit() is called.

Public Domain | Page generated by Ddoc.


std.socket

Notes:
For Win32 systems, link with ws2_32.lib.

Example:
See /dmd/samples/d/listener.d.

Authors:
Christopher E. Miller

Source:
std/socket.d

class SocketException: object.Exception;
Base exception thrown from a Socket.

int errorCode;
Platform-specific error code.

enum AddressFamily;
The communication domain used to resolve an address.

UNSPEC

UNIX
local communication

INET
internet protocol version 4

IPX
novell IPX

APPLETALK
appletalk

enum SocketType;
Communication semantics

STREAM
sequenced, reliable, two-way communication-based byte streams

DGRAM
connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order

RAW
raw protocol access

RDM
reliably-delivered message datagrams

SEQPACKET
sequenced, reliable, two-way connection-based datagrams with a fixed maximum length

enum ProtocolType;
Protocol

IP
internet protocol version 4

ICMP
internet control message protocol

IGMP
internet group management protocol

GGP
gateway to gateway protocol

TCP
transmission control protocol

PUP
PARC universal packet protocol

UDP
user datagram protocol

IDP
Xerox NS protocol

IPV6
internet protocol version 6

class Protocol;
Protocol is a class for retrieving protocol information.

ProtocolType type;
string name;
string[] aliases;
These members are populated when one of the following functions are called without failure:

bool getProtocolByName(string name);
Returns false on failure

bool getProtocolByType(ProtocolType type);
Returns false on failure

class Service;
Service is a class for retrieving service information.

string name;
string[] aliases;
ushort port;
string protocolName;
These members are populated when one of the following functions are called without failure:

bool getServiceByName(string name, string protocolName);
bool getServiceByName(string name);
bool getServiceByPort(ushort port, string protocolName);
bool getServiceByPort(ushort port);
If a protocol name is omitted, any protocol will be matched.

Returns:
false on failure.

class HostException: object.Exception;
Base exception thrown from an InternetHost.

int errorCode;
Platform-specific error code.

class InternetHost;
InternetHost is a class for resolving IPv4 addresses.

string name;
string[] aliases;
uint32_t[] addrList;
These members are populated when one of the following functions are called without failure:

bool getHostByName(string name);
Resolve host name. Returns false if unable to resolve.

bool getHostByAddr(uint addr);
Resolve IPv4 address number. Returns false if unable to resolve.

bool getHostByAddr(string addr);
Same as previous, but addr is an IPv4 address string in the dotted-decimal form a.b.c.d. Returns false if unable to resolve.

class AddressException: object.Exception;
Base exception thrown from an Address.

abstract class Address;
Address is an abstract class for representing a network addresses.

AddressFamily addressFamily();
Family of this address.

string toString();
Human readable string representing this address.

class UnknownAddress: std.socket.Address;

class InternetAddress: std.socket.Address;
InternetAddress is a class that represents an IPv4 (internet protocol version 4) address and port.

const uint ADDR_ANY;
Any IPv4 address number.

const uint ADDR_NONE;
An invalid IPv4 address number.

const ushort PORT_ANY;
Any IPv4 port number.

AddressFamily addressFamily();
Overridden to return AddressFamily.INET.

ushort port();
Returns the IPv4 port number.

uint addr();
Returns the IPv4 address number.

this(string addr, ushort port);
Params:
string addr | an IPv4 address string in the dotted-decimal form a.b.c.d, or a host name that will be resolved using an InternetHost object.
ushort port | may be PORT_ANY as stated below.

this(uint addr, ushort port);
this(ushort port);
Construct a new Address. addr may be ADDR_ANY (default) and port may be PORT_ANY, and the actual numbers may not be known until a connection is made.

string toAddrString();
Human readable string representing the IPv4 address in dotted-decimal form.

string toPortString();
Human readable string representing the IPv4 port.

string toString();
Human readable string representing the IPv4 address and port in the form a.b.c.d:e.

static uint parse(string addr);
Parse an IPv4 address string in the dotted-decimal form a.b.c.d and return the number. If the string is not a legitimate IPv4 address, ADDR_NONE is returned.

class SocketAcceptException: std.socket.SocketException;

enum SocketShutdown;
How a socket is shutdown:

RECEIVE
socket receives are disallowed

SEND
socket sends are disallowed

BOTH
both RECEIVE and SEND

enum SocketFlags;
Flags may be OR'ed together:

NONE
no flags specified

OOB
out-of-band stream data

PEEK
peek at incoming data without removing it from the queue, only for receiving

DONTROUTE
data should not be subject to routing; this flag may be ignored. Only for sending

NOSIGNAL
don't send SIGPIPE signal on socket write error and instead return EPIPE

struct timeval;
Duration timeout value.

int seconds;
Number of seconds.

int microseconds;
Number of additional microseconds.

class SocketSet;
A collection of sockets for use with Socket.select.

this(uint max);
Set the maximum amount of sockets that may be added.

this();
Uses the default maximum for the system.

void reset();
Reset the SocketSet so that there are 0 Sockets in the collection.

void add(Socket s);
Add a Socket to the collection. Adding more than the maximum has dangerous side affects.

void remove(Socket s);
Remove this Socket from the collection.

int isSet(Socket s);
Returns nonzero if this Socket is in the collection.

uint max();
Return maximum amount of sockets that can be added, like FD_SETSIZE.

enum SocketOptionLevel;
The level at which a socket option is defined:

SOCKET
socket level

IP
internet protocol version 4 level

ICMP

IGMP

GGP

TCP
transmission control protocol level

PUP

UDP
user datagram protocol level

IDP

IPV6
internet protocol version 6 level

struct linger;
Linger information for use with SocketOption.LINGER.

uint16_t on;
Nonzero for on.

uint16_t time;
Linger time.

enum SocketOption;
Specifies a socket option:

DEBUG
record debugging information

BROADCAST
allow transmission of broadcast messages

REUSEADDR
allow local reuse of address

LINGER
linger on close if unsent data is present

OOBINLINE
receive out-of-band data in band

SNDBUF
send buffer size

RCVBUF
receive buffer size

DONTROUTE
do not route

TCP_NODELAY
disable the Nagle algorithm for send coalescing

IPV6_UNICAST_HOPS

IPV6_MULTICAST_IF

IPV6_MULTICAST_LOOP

IPV6_JOIN_GROUP

IPV6_LEAVE_GROUP

class Socket;
Socket is a class that creates a network communication endpoint using the Berkeley sockets interface.

this(AddressFamily af, SocketType type, ProtocolType protocol);
this(AddressFamily af, SocketType type);
this(AddressFamily af, SocketType type, string protocolName);
Create a blocking socket. If a single protocol type exists to support this socket type within the address family, the ProtocolType may be omitted.

socket_t handle();
Get underlying socket handle.

bool blocking();
void blocking(bool byes);
Get/set socket's blocking flag.

When a socket is blocking, calls to receive(), accept(), and send() will block and wait for data/action. A non-blocking socket will immediately return instead of blocking.

AddressFamily addressFamily();
Get the socket's address family.

bool isAlive();
Property that indicates if this is a valid, alive socket.

void bind(Address addr);
Associate a local address with this socket.

void connect(Address to);
Establish a connection. If the socket is blocking, connect waits for the connection to be made. If the socket is nonblocking, connect returns immediately and the connection attempt is still in progress.

void listen(int backlog);
Listen for an incoming connection. bind must be called before you can listen. The backlog is a request of how many pending incoming connections are queued until accept'ed.

protected Socket accepting();
Called by accept when a new Socket must be created for a new connection. To use a derived class, override this method and return an instance of your class. The returned Socket's handle must not be set; Socket has a protected constructor this() to use in this situation.

Socket accept();
Accept an incoming connection. If the socket is blocking, accept waits for a connection request. Throws SocketAcceptException if unable to accept. See accepting for use with derived classes.

void shutdown(SocketShutdown how);
Disables sends and/or receives.

void close();
Immediately drop any connections and release socket resources. Calling shutdown before close is recommended for connection-oriented sockets. The Socket object is no longer usable after close.

static string hostName();
Returns the local machine's host name. Idea from mango.

Address remoteAddress();
Remote endpoint Address.

Address localAddress();
Local endpoint Address.

const int ERROR;
Send or receive error code.

ssize_t send(void[] buf, SocketFlags flags);
ssize_t send(void[] buf);
Send data on the connection. Returns the number of bytes actually sent, or ERROR on failure. If the socket is blocking and there is no buffer space left, send waits.

ssize_t sendTo(void[] buf, SocketFlags flags, Address to);
ssize_t sendTo(void[] buf, Address to);
ssize_t sendTo(void[] buf, SocketFlags flags);
ssize_t sendTo(void[] buf);
Send data to a specific destination Address. If the destination address is not specified, a connection must have been made and that address is used. If the socket is blocking and there is no buffer space left, sendTo waits.

ssize_t receive(void[] buf, SocketFlags flags);
ssize_t receive(void[] buf);
Receive data on the connection. Returns the number of bytes actually received, 0 if the remote side has closed the connection, or ERROR on failure. If the socket is blocking, receive waits until there is data to be received.

ssize_t receiveFrom(void[] buf, SocketFlags flags, out Address from);
ssize_t receiveFrom(void[] buf, out Address from);
ssize_t receiveFrom(void[] buf, SocketFlags flags);
ssize_t receiveFrom(void[] buf);
Receive data and get the remote endpoint Address. If the socket is blocking, receiveFrom waits until there is data to be received.

Returns:
the number of bytes actually received, 0 if the remote side has closed the connection, or ERROR on failure.

int getOption(SocketOptionLevel level, SocketOption option, void[] result);
Get a socket option. Returns the number of bytes written to result.

int getOption(SocketOptionLevel level, SocketOption option, out int32_t result);
Common case of getting integer and boolean options.

int getOption(SocketOptionLevel level, SocketOption option, out linger result);
Get the linger option.

void setOption(SocketOptionLevel level, SocketOption option, int32_t value);
Common case for setting integer and boolean options.

void setOption(SocketOptionLevel level, SocketOption option, linger value);
Set the linger option.

static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, timeval* tv);
static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, int microseconds);
static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError);
Wait for a socket to change status. A wait timeout timeval or int microseconds may be specified; if a timeout is not specified or the timeval is null, the maximum timeout is used. The timeval timeout has an unspecified value when select returns. Returns the number of sockets with status changes, 0 on timeout, or -1 on interruption. If the return value is greater than 0, the SocketSets are updated to only contain the sockets having status changes. For a connecting socket, a write status change means the connection is established and it's able to send. For a listening socket, a read status change means there is an incoming connection request and it's able to accept.

class TcpSocket: std.socket.Socket;
TcpSocket is a shortcut class for a TCP Socket.

this(AddressFamily family);
Constructs a blocking TCP Socket.

this();
Constructs a blocking TCP Socket.

this(Address connectTo);
Constructs a blocking TCP Socket and connects to an InternetAddress.

class UdpSocket: std.socket.Socket;
UdpSocket is a shortcut class for a UDP Socket.

this(AddressFamily family);
Constructs a blocking UDP Socket.

this();
Constructs a blocking UDP Socket.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.socketstream

SocketStream is a stream for a blocking, connected Socket.

For Win32 systems, link with ws2_32.lib.

Example:
See /dmd/samples/d/htmlget.d

Authors:
Christopher E. Miller

References:
std.stream

Source:
std/socketstream.d

class SocketStream: std.stream.Stream;
SocketStream is a stream for a blocking, connected Socket.

this(Socket sock, FileMode mode);
Constructs a SocketStream with the specified Socket and FileMode flags.

this(Socket sock);
Uses mode FileMode.In | FileMode.Out.

Socket socket();
Property to get the Socket that is being streamed.

size_t readBlock(void* _buffer, size_t size);
Attempts to read the entire block, waiting if necessary.

size_t writeBlock(void* _buffer, size_t size);
Attempts to write the entire block, waiting if necessary.

ulong seek(long offset, SeekPos whence);

char[] toString();
Does not return the entire stream because that would require the remote connection to be closed.

void close();
Close the Socket.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.stdint

D constrains integral types to specific sizes. But efficiency of different sizes varies from machine to machine, pointer sizes vary, and the maximum integer size varies. stdint offers a portable way of trading off size vs efficiency, in a manner compatible with the stdint.h definitions in C.

The exact aliases are types of exactly the specified number of bits. The at least aliases are at least the specified number of bits large, and can be larger. The fast aliases are the fastest integral type supported by the processor that is at least as wide as the specified number of bits.

The aliases are:

Exact Alias | Description | At Least Alias | Description | Fast Alias | Description
int8_t | exactly 8 bits signed | int_least8_t | at least 8 bits signed | int_fast8_t | fast 8 bits signed
uint8_t | exactly 8 bits unsigned | uint_least8_t | at least 8 bits unsigned | uint_fast8_t | fast 8 bits unsigned
int16_t | exactly 16 bits signed | int_least16_t | at least 16 bits signed | int_fast16_t | fast 16 bits signed
uint16_t | exactly 16 bits unsigned | uint_least16_t | at least 16 bits unsigned | uint_fast16_t | fast 16 bits unsigned
int32_t | exactly 32 bits signed | int_least32_t | at least 32 bits signed | int_fast32_t | fast 32 bits signed
uint32_t | exactly 32 bits unsigned | uint_least32_t | at least 32 bits unsigned | uint_fast32_t | fast 32 bits unsigned
int64_t | exactly 64 bits signed | int_least64_t | at least 64 bits signed | int_fast64_t | fast 64 bits signed
uint64_t | exactly 64 bits unsigned | uint_least64_t | at least 64 bits unsigned | uint_fast64_t | fast 64 bits unsigned

The ptr aliases are integral types guaranteed to be large enough to hold a pointer without losing bits:

Alias | Description
intptr_t | signed integral type large enough to hold a pointer
uintptr_t | unsigned integral type large enough to hold a pointer

The max aliases are the largest integral types:

Alias | Description
intmax_t | the largest signed integral type
uintmax_t | the largest unsigned integral type

Authors:
Walter Bright, http://www.digitalmars.com

License:
Public Domain

Source:
std/stdint.d

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.stdio

Standard I/O functions that extend std.c.stdio. std.c.stdio is automatically imported when importing std.stdio.

Source:
std/stdio.d

class StdioException: object.Exception;
Thrown if I/O errors happen.

void writef(...);
Arguments are formatted per the format strings and written to stdout.

void writefln(...);
Same as writef, but a newline is appended to the output.

void fwritef(_iobuf* fp, ...);
Same as writef, but output is sent to the stream fp instead of stdout.

void fwritefln(_iobuf* fp, ...);
Same as writefln, but output is sent to the stream fp instead of stdout.

string readln(_iobuf* fp = stdin);
Read line from stream fp.

Returns:
null for end of file, char[] for line read from fp, including terminating '\n'

Params:
_iobuf* fp input stream

Throws:
StdioException on error

Example:
Reads stdin and writes it to stdout.
import std.stdio;

int main()
{
    char[] buf;
    while ((buf = readln()) != null)
        writef("%s", buf);
    return 0;
}

size_t readln(_iobuf* fp, ref char[] buf);
size_t readln(ref char[] buf);
Read line from stream fp and write it to buf[], including terminating '\n'.

This is often faster than readln(FILE*) because the buffer is reused each call. Note that reusing the buffer means that the previous contents of it need to be copied if needed.

Params:
_iobuf* fp | input stream
char[] buf | buffer used to store the resulting line data. buf is resized as necessary.

Returns:
0 for end of file, otherwise number of characters read

Throws:
StdioException on error

Example:
Reads stdin and writes it to stdout.
import std.stdio;

int main()
{
    char[] buf;
    while (readln(stdin, buf))
        writef("%s", buf);
    return 0;
}

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.cstream

The std.cstream module bridges std.c.stdio (or std.stdio) and std.stream. Both std.c.stdio and std.stream are publicly imported by std.cstream.

Authors:
Ben Hinkle

License:
Public Domain

Source:
std/cstream.d

class CFile: std.stream.Stream;
A Stream wrapper for a C file of type FILE*.

this(_iobuf* cfile, FileMode mode, bool seekable = false);
Create the stream wrapper for the given C file.

Params:
FileMode mode | a bitwise combination of FileMode.In for a readable file and FileMode.Out for a writeable file.
bool seekable | indicates if the stream should be seekable.

_iobuf* file();
void file(_iobuf* cfile);
Property to get or set the underlying file for this stream. Setting the file marks the stream as open.

void flush();
void close();
bool eof();
char getc();
char ungetc(char c);
size_t readBlock(void* buffer, size_t size);
size_t writeBlock(void* buffer, size_t size);
ulong seek(long offset, SeekPos rel);
void writeLine(char[] s);
void writeLineW(wchar[] s);
Overrides of the Stream methods to call the underlying FILE* C functions.

CFile din;
CFile wrapper of std.c.stdio.stdin (not seekable).

CFile dout;
CFile wrapper of std.c.stdio.stdout (not seekable).

CFile derr;
CFile wrapper of std.c.stdio.stderr (not seekable).

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.stream

Source:
std/stream.d

class StreamException: object.Exception;
A base class for stream exceptions.

this(string msg);
Construct a StreamException with given error message.

class ReadException: std.stream.StreamException;
Thrown when unable to read data from Stream.

this(string msg);
Construct a ReadException with given error message.

class WriteException: std.stream.StreamException;
Thrown when unable to write data to Stream.

this(string msg);
Construct a WriteException with given error message.

class SeekException: std.stream.StreamException;
Thrown when unable to move Stream pointer.

this(string msg);
Construct a SeekException with given error message.

abstract interface InputStream;
InputStream is the interface for readable streams.

abstract void readExact(void* buffer, size_t size);
Read exactly size bytes into the buffer.

Throws a ReadException if it is not correct.

abstract size_t read(ubyte[] buffer);
Read a block of data big enough to fill the given array buffer.

Returns:
the actual number of bytes read. Unfilled bytes are not modified.

abstract void read(out byte x);
abstract void read(out ubyte x);
abstract void read(out short x);
abstract void read(out ushort x);
abstract void read(out int x);
abstract void read(out uint x);
abstract void read(out long x);
abstract void read(out ulong x);
abstract void read(out float x);
abstract void read(out double x);
abstract void read(out real x);
abstract void read(out ifloat x);
abstract void read(out idouble x);
abstract void read(out ireal x);
abstract void read(out cfloat x);
abstract void read(out cdouble x);
abstract void read(out creal x);
abstract void read(out char x);
abstract void read(out wchar x);
abstract void read(out dchar x);
abstract void read(out char[] s);
abstract void read(out wchar[] s);
Read a basic type or counted string.

Throw a ReadException if it could not be read. Outside of byte, ubyte, and char, the format is implementation-specific and should not be used except as opposite actions to write.

abstract char[] readLine();
abstract char[] readLine(char[] result);
abstract wchar[] readLineW();
abstract wchar[] readLineW(wchar[] result);
Read a line that is terminated with some combination of carriage return and line feed or end-of-file.

The terminators are not included. The wchar version is identical. The optional buffer parameter is filled (reallocating it if necessary) and a slice of the result is returned.

abstract int opApply(int delegate(ref char[] line) dg);
abstract int opApply(int delegate(ref ulong n, ref char[] line) dg);
abstract int opApply(int delegate(ref wchar[] line) dg);
abstract int opApply(int delegate(ref ulong n, ref wchar[] line) dg);
Overload foreach statements to read the stream line by line and call the supplied delegate with each line or with each line with line number.

The string passed in line may be reused between calls to the delegate. Line numbering starts at 1. Breaking out of the foreach will leave the stream position at the beginning of the next line to be read. For example, to echo a file line-by-line with line numbers run:
 Stream file = new BufferedFile("sample.txt");
 foreach(ulong n, string line; file) {
   stdout.writefln("line %d: %s",n,line);
 }
 file.close();

abstract char[] readString(size_t length);
Read a string of the given length, throwing ReadException if there was a problem.

abstract wchar[] readStringW(size_t length);
Read a string of the given length, throwing ReadException if there was a problem.

The file format is implementation-specific and should not be used except as opposite actions to write.

abstract char getc();
abstract wchar getcw();
Read and return the next character in the stream.

This is the only method that will handle ungetc properly. getcw's format is implementation-specific. If EOF is reached then getc returns char.init and getcw returns wchar.init.

abstract char ungetc(char c);
abstract wchar ungetcw(wchar c);
Push a character back onto the stream.

They will be returned in first-in last-out order from getc/getcw. Only has effect on further calls to getc() and getcw().

abstract int vreadf(TypeInfo[] arguments, va_list args);
abstract int readf(...);
Scan a string from the input using a similar form to C's scanf and std.format.

An argument of type string is interpreted as a format string. All other arguments must be pointer types. If a format string is not present a default will be supplied computed from the base type of the pointer type. An argument of type string* is filled (possibly with appending characters) and a slice of the result is assigned back into the argument. For example the following readf statements are equivalent:
 int x;
 double y;
 string s;
 file.readf(&x, " hello ", &y, &s);
 file.readf("%d hello %f %s", &x, &y, &s);
 file.readf("%d hello %f", &x, &y, "%s", &s);

abstract size_t available();
Retrieve the number of bytes available for immediate reading.

abstract bool eof();
Return whether the current file position is the same as the end of the file.

This does not require actually reading past the end, as with stdio. For non-seekable streams this might only return true after attempting to read past the end.

abstract bool isOpen();
Return true if the stream is currently open.

abstract interface OutputStream;
Interface for writable streams.

abstract void writeExact(void* buffer, size_t size);
Write exactly size bytes from buffer, or throw a WriteException if that could not be done.

abstract size_t write(ubyte[] buffer);
Write as much of the buffer as possible, returning the number of bytes written.

abstract void write(byte x);
abstract void write(ubyte x);
abstract void write(short x);
abstract void write(ushort x);
abstract void write(int x);
abstract void write(uint x);
abstract void write(long x);
abstract void write(ulong x);
abstract void write(float x);
abstract void write(double x);
abstract void write(real x);
abstract void write(ifloat x);
abstract void write(idouble x);
abstract void write(ireal x);
abstract void write(cfloat x);
abstract void write(cdouble x);
abstract void write(creal x);
abstract void write(char x);
abstract void write(wchar x);
abstract void write(dchar x);
Write a basic type.

Outside of byte, ubyte, and char, the format is implementation-specific and should only be used in conjunction with read. Throw WriteException on error.

abstract void write(char[] s);
abstract void write(wchar[] s);
Writes a string, together with its length.

The format is implementation-specific and should only be used in conjunction with read. Throw WriteException on error.

abstract void writeLine(char[] s);
Write a line of text, appending the line with an operating-system-specific line ending.

Throws WriteException on error.

abstract void writeLineW(wchar[] s);
Write a line of text, appending the line with an operating-system-specific line ending.

The format is implementation-specific. Throws WriteException on error.

abstract void writeString(char[] s);
Write a string of text.

Throws WriteException if it could not be fully written.

abstract void writeStringW(wchar[] s);
Write a string of text.

The format is implementation-specific. Throws WriteException if it could not be fully written.

abstract size_t vprintf(char[] format, va_list args);
abstract size_t printf(char[] format, ...);
Print a formatted string into the stream using printf-style syntax, returning the number of bytes written.

abstract OutputStream writef(...);
abstract OutputStream writefln(...);
abstract OutputStream writefx(TypeInfo[] arguments, void* argptr, int newline = false);
Print a formatted string into the stream using writef-style syntax.

References:
std.format.

Returns:
self to chain with other stream commands like flush.

abstract void flush();
Flush pending output if appropriate.

abstract void close();
Close the stream, flushing output if appropriate.

abstract bool isOpen();
Return true if the stream is currently open.

abstract class Stream: std.stream.InputStream, std.stream.OutputStream;
Stream is the base abstract class from which the other stream classes derive.

Stream's byte order is the format native to the computer.

Reading:
These methods require that the readable flag be set. Problems with reading result in a ReadException being thrown. Stream implements the InputStream interface in addition to the readBlock method.

Writing:
These methods require that the writeable flag be set. Problems with writing result in a WriteException being thrown. Stream implements the OutputStream interface in addition to the following methods: writeBlock copyFrom copyFrom

Seeking:
These methods require that the seekable flag be set. Problems with seeking result in a SeekException being thrown. seek, seekSet, seekCur, seekEnd, position, size, toString, toHash

bool readable;
Indicates whether this stream can be read from.

bool writeable;
Indicates whether this stream can be written to.

bool seekable;
Indicates whether this stream can be seeked within.

protected bool isopen;
Indicates whether this stream is open.

protected bool readEOF;
Indicates whether this stream is at eof after the last read attempt.

protected bool prevCr;
For a non-seekable stream indicates that the last readLine or readLineW ended on a '\r' character.

abstract size_t readBlock(void* buffer, size_t size);
Read up to size bytes into the buffer and return the number of bytes actually read. A return value of 0 indicates end-of-file.

abstract size_t writeBlock(void* buffer, size_t size);
Write up to size bytes from buffer in the stream, returning the actual number of bytes that were written.

void copyFrom(Stream s);
Copies all data from s into this stream. This may throw ReadException or WriteException on failure. This restores the file position of s so that it is unchanged.

void copyFrom(Stream s, ulong count);
Copy a specified number of bytes from the given stream into this one. This may throw ReadException or WriteException on failure. Unlike the previous form, this doesn't restore the file position of s.

abstract ulong seek(long offset, SeekPos whence);
Change the current position of the stream. whence is either SeekPos.Set, in which case the offset is an absolute index from the beginning of the stream, SeekPos.Current, in which case the offset is a delta from the current position, or SeekPos.End, in which case the offset is a delta from the end of the stream (negative or zero offsets only make sense in that case). This returns the new file position.

ulong seekSet(long offset);
ulong seekCur(long offset);
ulong seekEnd(long offset);
Aliases for their normal seek counterparts.

void position(ulong pos);
Sets file position. Equivalent to calling seek(pos, SeekPos.Set).

ulong position();
Returns current file position. Equivalent to seek(0, SeekPos.Current).

ulong size();
Retrieve the size of the stream in bytes. The stream must be seekable or a SeekException is thrown.

string toString();
Read the entire stream and return it as a string. If the stream is not seekable the contents from the current position to eof is read and returned.

size_t toHash();
Get a hash of the stream by reading each byte and using it in a CRC-32 checksum.

class FilterStream: std.stream.Stream;
A base class for streams that wrap a source stream with additional functionality.

The method implementations forward read/write/seek calls to the source stream. A FilterStream can change the position of the source stream arbitrarily and may not keep the source stream state in sync with the FilterStream, even upon flushing and closing the FilterStream. It is recommended to not make any assumptions about the state of the source position and read/write state after a FilterStream has acted upon it. Specifc subclasses of FilterStream should document how they modify the source stream and if any invariants hold true between the source and filter.

bool nestClose;
Property indicating when this stream closes to close the source stream as well. Defaults to true.

this(Stream source);
Construct a FilterStream for the given source.

final Stream source();
Get the current source stream.

void source(Stream s);
Set the current source stream.

Setting the source stream closes this stream before attaching the new source. Attaching an open stream reopens this stream and resets the stream state.

void resetSource();
Indicates the source stream changed state and that this stream should reset any readable, writeable, seekable, isopen and buffering flags.

class BufferedStream: std.stream.FilterStream;
This subclass is for buffering a source stream.

A buffered stream must be closed explicitly to ensure the final buffer content is written to the source stream. The source stream position is changed according to the block size so reading or writing to the BufferedStream may not change the source stream position by the same amount.

this(Stream source, uint bufferSize = DefaultBufferSize);
Create a buffered stream for the stream source with the buffer size bufferSize.

class StreamFileException: std.stream.StreamException;
An exception for File errors.

this(string msg);
Construct a StreamFileException with given error message.

class OpenException: std.stream.StreamFileException;
An exception for errors during File.open.

this(string msg);
Construct an OpenFileException with given error message.

class File: std.stream.Stream;
This subclass is for unbuffered file system streams.

this(string filename, FileMode mode = (FileMode).In);
Create the stream with no open file, an open file in read mode, or an open file with explicit file mode. mode, if given, is a combination of FileMode.In (indicating a file that can be read) and FileMode.Out (indicating a file that can be written). Opening a file for reading that doesn't exist will error. Opening a file for writing that doesn't exist will create the file. The FileMode.OutNew mode will open the file for writing and reset the length to zero. The FileMode.Append mode will open the file for writing and move the file position to the end of the file.

void open(string filename, FileMode mode = (FileMode).In);
Open a file for the stream, in an identical manner to the constructors. If an error occurs an OpenException is thrown.

void create(string filename);
void create(string filename, FileMode mode);
Create a file for writing.

void close();
Close the current file if it is open; otherwise it does nothing.

size_t available();
For a seekable file returns the difference of the size and position and otherwise returns 0.

class BufferedFile: std.stream.BufferedStream;
This subclass is for buffered file system streams.

It is a convenience class for wrapping a File in a BufferedStream. A buffered stream must be closed explicitly to ensure the final buffer content is written to the file.

this();
opens file for reading

this(string filename, FileMode mode = (FileMode).In, uint bufferSize = DefaultBufferSize);
opens file in requested mode and buffer size

this(File file, uint bufferSize = DefaultBufferSize);
opens file for reading with requested buffer size

this(HANDLE hFile, FileMode mode, uint buffersize);
opens existing handle; use with care!

void open(string filename, FileMode mode = (FileMode).In);
opens file in requested mode

void create(string filename, FileMode mode = (FileMode).OutNew);
creates file in requested mode

enum BOM;
UTF byte-order-mark signatures

UTF8
UTF-8

UTF16LE
UTF-16 Little Endian

UTF16BE
UTF-16 Big Endian

UTF32LE
UTF-32 Little Endian

UTF32BE
UTF-32 Big Endian

class EndianStream: std.stream.FilterStream;
This subclass wraps a stream with big-endian or little-endian byte order swapping.

UTF Byte-Order-Mark (BOM) signatures can be read and deduced or written. Note that an EndianStream should not be used as the source of another FilterStream since a FilterStream call the source with byte-oriented read/write requests and the EndianStream will not perform any byte swapping. The EndianStream reads and writes binary data (non-getc functions) in a one-to-one manner with the source stream so the source stream's position and state will be kept in sync with the EndianStream if only non-getc functions are called.

Endian endian;
Endianness property of the source stream.

this(Stream source, Endian end = module system.endian);
Create the endian stream for the source stream source with endianness end. The default endianness is the native byte order. The Endian type is defined in the std.system module.

int readBOM(int ungetCharSize = 1);
Return -1 if no BOM and otherwise read the BOM and return it.

If there is no BOM or if bytes beyond the BOM are read then the bytes read are pushed back onto the ungetc buffer or ungetcw buffer. Pass ungetCharSize == 2 to use ungetcw instead of ungetc when no BOM is present.

final void fixBO(void* buffer, size_t size);
Correct the byte order of buffer to match native endianness. size must be even.

final void fixBlockBO(void* buffer, uint size, size_t repeat);
Correct the byte order of the given buffer in blocks of the given size and repeated the given number of times. size must be even.

void writeBOM(BOM b);
Write the specified BOM b to the source stream.

class TArrayStream(Buffer): Stream;
Parameterized subclass that wraps an array-like buffer with a stream interface.

The type Buffer must support the length property, opIndex and opSlice. Compile in release mode when directly instantiating a TArrayStream to avoid link errors.

this(Buffer buf);
Create the stream for the the buffer buf. Non-copying.

ubyte[] data();
Get the current memory data in total.

class MemoryStream: std.stream.TArrayStream!(ubyte[]).TArrayStream;
This subclass reads and constructs an array of bytes in memory.

this();
Create the output buffer and setup for reading, writing, and seeking.

this(ubyte[] buf);
this(byte[] buf);
this(char[] buf);
Create the output buffer and setup for reading, writing, and seeking. Load it with specific input data.

void reserve(size_t count);
Ensure the stream can hold count bytes.

class MmFileStream: std.stream.TArrayStream!(MmFile).TArrayStream;
This subclass wraps a memory-mapped file with the stream API. See std.mmfile module.

this(MmFile file);
Create stream wrapper for file.

class SliceStream: std.stream.FilterStream;
This subclass slices off a portion of another stream, making seeking relative to the boundaries of the slice.

It could be used to section a large file into a set of smaller files, such as with tar archives. Reading and writing a SliceStream does not modify the position of the source stream if it is seekable.

this(Stream s, ulong low);
Indicate both the source stream to use for reading from and the low part of the slice.

The high part of the slice is dependent upon the end of the source stream, so that if you write beyond the end it resizes the stream normally.

this(Stream s, ulong low, ulong high);
Indicate the high index as well.

Attempting to read or write past the high index results in the end being clipped off.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.string

String handling functions.

To copy or not to copy? When a function takes a string as a parameter, and returns a string, is that string the same as the input string, modified in place, or is it a modified copy of the input string? The D array convention is "copy-on-write". This means that if no modifications are done, the original string (or slices of it) can be returned. If any modifications are done, the returned string is a copy.

Source:
std/string.d

class StringException: object.Exception;
Thrown on errors in string functions.

const char[16u] hexdigits;
0..9A..F

const char[10u] digits;
0..9

const char[8u] octdigits;
0..7

const char[26u] lowercase;
a..z

const char[26u] uppercase;
A..Z

const char[52u] letters;
A..Za..z

const char[6u] whitespace;
ASCII whitespace

const dchar LS;
UTF line separator

const dchar PS;
UTF paragraph separator

const char[2u] newline;
Newline sequence for this system

bool iswhite(dchar c);
Returns true if c is whitespace

long atoi(char[] s);
Convert string to integer.

real atof(char[] s);
Convert string to real.

int cmp(char[] s1, char[] s2);
int icmp(char[] s1, char[] s2);
Compare two strings. cmp is case sensitive, icmp is case insensitive.

Returns:
< 0 | s1 < s2
= 0 | s1 == s2
> 0 | s1 > s2

char* toStringz(char[] s);
Convert array of chars s[] to a C-style 0 terminated string. s[] must not contain embedded 0's.

ptrdiff_t find(char[] s, dchar c);
ptrdiff_t ifind(char[] s, dchar c);
ptrdiff_t rfind(char[] s, dchar c);
ptrdiff_t irfind(char[] s, dchar c);
find, ifind find first occurrence of c in string s. rfind, irfind find last occurrence of c in string s.

find, rfind are case sensitive; ifind, irfind are case insensitive.

Returns:
Index in s where c is found, -1 if not found.

ptrdiff_t find(char[] s, char[] sub);
ptrdiff_t ifind(char[] s, char[] sub);
ptrdiff_t rfind(char[] s, char[] sub);
ptrdiff_t irfind(char[] s, char[] sub);
find, ifind find first occurrence of sub[] in string s[]. rfind, irfind find last occurrence of sub[] in string s[].

find, rfind are case sensitive; ifind, irfind are case insensitive.

Returns:
Index in s where c is found, -1 if not found.

string tolower(string s);
Convert string s[] to lower case.

string toupper(string s);
Convert string s[] to upper case.

char[] capitalize(char[] s);
Capitalize first character of string s[], convert rest of string s[] to lower case.

char[] capwords(char[] s);
Capitalize all words in string s[]. Remove leading and trailing whitespace. Replace all sequences of whitespace with a single space.

char[] repeat(char[] s, size_t n);
Return a string that consists of s[] repeated n times.

char[] join(char[][] words, char[] sep);
Concatenate all the strings in words[] together into one string; use sep[] as the separator.

char[][] split(char[] s);
Split s[] into an array of words, using whitespace as the delimiter.

char[][] split(char[] s, char[] delim);
Split s[] into an array of words, using delim[] as the delimiter.

char[][] splitlines(char[] s);
Split s[] into an array of lines, using CR, LF, or CR-LF as the delimiter. The delimiter is not included in the line.

char[] stripl(char[] s);
char[] stripr(char[] s);
char[] strip(char[] s);
Strips leading or trailing whitespace, or both.

char[] chomp(char[] s, char[] delimiter = null);
Returns s[] sans trailing delimiter[], if any. If delimiter[] is null, removes trailing CR, LF, or CRLF, if any.

char[] chop(char[] s);
Returns s[] sans trailing character, if there is one. If last two characters are CR-LF, then both are removed.

char[] ljustify(char[] s, int width);
char[] rjustify(char[] s, int width);
char[] center(char[] s, int width);
Left justify, right justify, or center string s[] in field width chars wide.

char[] zfill(char[] s, int width);
Same as rjustify(), but fill with '0's.

char[] replace(char[] s, char[] from, char[] to);
Replace occurrences of from[] with to[] in s[].

char[] replaceSlice(char[] string, char[] slice, char[] replacement);
Return a string that is string[] with slice[] replaced by replacement[].

char[] insert(char[] s, size_t index, char[] sub);
Insert sub[] into s[] at location index.

size_t count(char[] s, char[] sub);
Count up all instances of sub[] in s[].

char[] expandtabs(char[] string, int tabsize = 8);
Replace tabs with the appropriate number of spaces. tabsize is the distance between tab stops.

char[] entab(char[] string, int tabsize = 8);
Replace spaces in string with the optimal number of tabs. Trailing spaces or tabs in a line are removed.

Params:
char[] string | String to convert.
int tabsize | Tab columns are tabsize spaces apart. tabsize defaults to 8.

char[] maketrans(char[] from, char[] to);
Construct translation table for translate().

BUG:
only works with ASCII

char[] translate(char[] s, char[] transtab, char[] delchars);
Translate characters in s[] using table created by maketrans(). Delete chars in delchars[].

BUG:
only works with ASCII

char[] toString(bool b);
char[] toString(char c);
char[] toString(ubyte ub);
char[] toString(ushort us);
char[] toString(uint u);
char[] toString(ulong u);
char[] toString(byte b);
char[] toString(short s);
char[] toString(int i);
char[] toString(long i);
char[] toString(float f);
char[] toString(double d);
char[] toString(real r);
char[] toString(ifloat f);
char[] toString(idouble d);
char[] toString(ireal r);
char[] toString(cfloat f);
char[] toString(cdouble d);
char[] toString(creal r);
Convert to char[].

char[] toString(long value, uint radix);
char[] toString(ulong value, uint radix);
Convert value to string in radix radix.

radix must be a value from 2 to 36. value is treated as a signed value only if radix is 10. The characters A through Z are used to represent values 10 through 36.

char[] toString(char* s);
Convert C-style 0 terminated string s to char[] string.

char[] format(...);
Format arguments into a string.

char[] sformat(char[] s, ...);
Format arguments into string s which must be large enough to hold the result. Throws ArrayBoundsError if it is not.

Returns:
s

bool inPattern(dchar c, char[] pattern);
See if character c is in the pattern.

Patterns:
A pattern is an array of characters much like a character class in regular expressions. A sequence of characters can be given, such as "abcde". The '-' can represent a range of characters, as "a-e" represents the same pattern as "abcde". "a-fA-F0-9" represents all the hex characters. If the first character of a pattern is '^', then the pattern is negated, i.e. "^0-9" means any character except a digit. The functions inPattern, countchars, removeschars, and squeeze use patterns.

Note:
In the future, the pattern syntax may be improved to be more like regular expression character classes.

int inPattern(dchar c, char[][] patterns);
See if character c is in the intersection of the patterns.

size_t countchars(char[] s, char[] pattern);
Count characters in s that match pattern.

char[] removechars(char[] s, char[] pattern);
Return string that is s with all characters removed that match pattern.

char[] squeeze(char[] s, char[] pattern = null);
Return string where sequences of a character in s[] from pattern[] are replaced with a single instance of that character. If pattern is null, it defaults to all characters.

char[] succ(char[] s);
Return string that is the 'successor' to s[]. If the rightmost character is a-zA-Z0-9, it is incremented within its case or digits. If it generates a carry, the process is repeated with the one to its immediate left.

char[] tr(char[] str, char[] from, char[] to, char[] modifiers = null);
Replaces characters in str[] that are in from[] with corresponding characters in to[] and returns the resulting string.

Params:
char[] modifiers a string of modifier characters

Modifiers:
Modifier | Description
c | Complement the list of characters in from[]
d | Removes matching characters with no corresponding replacement in to[]
s | Removes adjacent duplicates in the replaced characters

If modifier d is present, then the number of characters in to[] may be only 0 or 1.

If modifier d is not present and to[] is null, then to[] is taken to be the same as from[].

If modifier d is not present and to[] is shorter than from[], then to[] is extended by replicating the last character in to[].

Both from[] and to[] may contain ranges using the - character, for example a-d is synonymous with abcd. Neither accept a leading ^ as meaning the complement of the string (use the c modifier for that).

final bool isNumeric(char[] s, bool bAllowSep = false);
[in] char[] s can be formatted in the following ways:

Integer Whole Number: (for byte, ubyte, short, ushort, int, uint, long, and ulong) ['+'|'-']digit(s)[U|L|UL]

Examples:
123, 123UL, 123L, +123U, -123L

Floating-Point Number: (for float, double, real, ifloat, idouble, and ireal) ['+'|'-']digit(s)[.][digit(s)][[e-|e+]digit(s)][i|f|L|Li|fi]] or [nan|nani|inf|-inf]

Examples:
+123., -123.01, 123.3e-10f, 123.3e-10fi, 123.3e-10L

(for cfloat, cdouble, and creal) ['+'|'-']digit(s)[.][digit(s)][[e-|e+]digit(s)][+] [digit(s)[.][digit(s)][[e-|e+]digit(s)][i|f|L|Li|fi]] or [nan|nani|nan+nani|inf|-inf]

Examples:
nan, -123e-1+456.9e-10Li, +123e+10+456i, 123+456

[in] bool bAllowSep False by default, but when set to true it will accept the separator characters "," and "" within the string, but these characters should be stripped from the string before using any of the conversion functions like toInt(), toFloat(), and etc else an error will occur.

Also please note, that no spaces are allowed within the string anywhere whether it's a leading, trailing, or embedded space(s), thus they too must be stripped from the string before using this function, or any of the conversion functions.

bool isNumeric(...);
Allow any object as a parameter

bool isNumeric(TypeInfo[] _arguments, va_list _argptr);
Check only the first parameter, all others will be ignored.

char[] soundex(char[] string, char[] buffer = null);
Soundex algorithm.

The Soundex algorithm converts a word into 4 characters based on how the word sounds phonetically. The idea is that two spellings that sound alike will have the same Soundex value, which means that Soundex can be used for fuzzy matching of names.

Params:
char[] string | String to convert to Soundex representation.
char[] buffer | Optional 4 char array to put the resulting Soundex characters into. If null, the return value buffer will be allocated on the heap.

Returns:
The four character array with the Soundex result in it. Returns null if there is no Soundex representation for the string.

See Also:
Wikipedia, The Soundex Indexing System

BUGS:
Only works well with English names. There are other arguably better Soundex algorithms, but this one is the standard one.

char[][char[]] abbrev(char[][] values);
Construct an associative array consisting of all abbreviations that uniquely map to the strings in values.

This is useful in cases where the user is expected to type in one of a known set of strings, and the program will helpfully autocomplete the string once sufficient characters have been entered that uniquely identify it.

Example:
 import std.stdio;
 import std.string;

 void main()
 {
    static char[][] list = [ "food", "foxy" ];

    auto abbrevs = std.string.abbrev(list);

    foreach (key, value; abbrevs)
    {
       writefln("%s => %s", key, value);
    }
 }
produces the output:
 fox => foxy
 food => food
 foxy => foxy
 foo => food

size_t column(char[] string, int tabsize = 8);
Compute column number after string if string starts in the leftmost column, which is numbered starting from 0.

char[] wrap(char[] s, int columns = 80, char[] firstindent = null, char[] indent = null, int tabsize = 8);
Wrap text into a paragraph.

The input text string s is formed into a paragraph by breaking it up into a sequence of lines, delineated by \n, such that the number of columns is not exceeded on each line. The last line is terminated with a \n.

Params:
char[] s | text string to be wrapped
int columns | maximum number of columns in the paragraph
char[] firstindent | string used to indent first line of the paragraph
char[] indent | string to use to indent following lines of the paragraph
int tabsize | column spacing of tabs

Returns:
The resulting paragraph.

char[] isEmail(char[] s);
Does string s[] start with an email address?

Returns:
null it does not char[] it does, and this is the slice of s[] that is that email address

References:
RFC2822

char[] isURL(char[] s);
Does string s[] start with a URL?

Returns:
null it does not char[] it does, and this is the slice of s[] that is that URL

Public Domain | Page generated by Ddoc.


std.system

Information about the target operating system, environment, and CPU

Authors:
Walter Bright, http://www.digitalmars.com

License:
Public Domain

Source:
std/system.d

enum Endian;
Byte order endianness

BigEndian
big endian byte order

LittleEndian
little endian byte order

const Endian endian;
Native system endianness

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.thread

The thread module defines the class Thread.

Thread is the basis for writing multithreaded applications. Each thread has a unique instance of class Thread associated with it. It is important to use the Thread class to create and manage threads as the garbage collector needs to know about all the threads.

Source:
std/thread.d

alias thread_hdl;
The type of the thread handle used by the operating system. For Windows, it is equivalent to a HANDLE from windows.d.

class ThreadError: object.Error;
Thrown for errors.

class Thread;
One of these is created for each thread.

this(size_t stacksize = 0);
Constructor used by classes derived from Thread that override main(). The optional stacksize parameter default value of 0 will cause threads to be created with the default size for the executable - Dave Fladebo

this(int function(void*) fp, void* arg, size_t stacksize = 0);
Constructor used by classes derived from Thread that override run().

this(int delegate() dg, size_t stacksize = 0);
Constructor used by classes derived from Thread that override run().

thread_hdl hdl;
The handle to this thread assigned by the operating system. This is set to thread_id.init if the thread hasn't been started yet.

void start();
Create a new thread and start it running. The new thread initializes itself and then calls run(). start() can only be called once.

int run();
Entry point for a thread. If not overridden, it calls the function pointer fp and argument arg passed in the constructor, or the delegate dg.

Returns:
the thread exit code, which is normally 0.

void wait();
Wait for this thread to terminate. Simply returns if thread has already terminated.

Throws:
ThreadError if the thread hasn't begun yet or is called on itself.

void wait(uint milliseconds);
Wait for this thread to terminate or until milliseconds time has elapsed, whichever occurs first. Simply returns if thread has already terminated.

Throws:
ThreadError if the thread hasn't begun yet or is called on itself.

enum TS;
The state of a thread.

INITIAL
The thread hasn't been started yet.

RUNNING
The thread is running or paused.

TERMINATED
The thread has ended.

FINISHED
The thread has been cleaned up

TS getState();
Returns the state of a thread.

enum PRIORITY;
The priority of a thread.

INCREASE
Increase thread priority

DECREASE
Decrease thread priority

IDLE
Assign thread low priority

CRITICAL
Assign thread high priority

void setPriority(PRIORITY p);
Adjust the priority of this thread.

Throws:
ThreadError if cannot set priority

bool isSelf();
Returns true if this thread is the current thread.

static Thread _getThreadById(thread_id id);
Returns a reference to the Thread with the given id

static Thread _getThis();
Returns a reference to the Thread for the thread that called the function.

static Thread[] getAll();
Returns an array of all the threads currently running.

void pause();
Suspend execution of this thread.

void resume();
Resume execution of this thread.

static void pauseAll();
Suspend execution of all threads but this thread.

static void resumeAll();
Resume execution of all paused threads.

static void yield();
Give up the remainder of this thread's time slice.

static uint nthreads;

static void thread_init();
Create a Thread for global main().

static void thread_attach();
Attach to current thread

static void thread_detach();
Detach from current thread

void* os_query_stackBottom();
Determine "bottom" of stack (actually the top on Windows systems).

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.traits

Templates with which to extract information about types at compile time.

Source:
std/traits.d

template ReturnType(alias dg)
template ReturnType(dg)
Get the type of the return value from a function, a pointer to function, or a delegate.

Example:
 import std.traits;
 int foo();
 ReturnType!(foo) x;   // x is declared as int

template ParameterTypeTuple(alias dg)
template ParameterTypeTuple(dg)
Get the types of the paramters to a function, a pointer to function, or a delegate as a tuple.

Example:
 import std.traits;
 int foo(int, long);
 void bar(ParameterTypeTuple!(foo));      // declares void bar(int, long);
 void abc(ParameterTypeTuple!(foo)[1]);   // declares void abc(long);

template FieldTypeTuple(S)
Get the types of the fields of a struct or class. This consists of the fields that take up memory space, excluding the hidden fields like the virtual function table pointer.

template BaseTypeTuple(A)
Get a TypeTuple of the base class and base interfaces of this class or interface.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }

 void main()
 {
     alias BaseTypeTuple!(B) TL;
     writefln(typeid(TL));    // prints: (A,I)
 }

template isStaticArray(T)
Detect whether type T is a static array.

template isExpressionTuple(T...)
Tells whether the tuple T is an expression tuple.

Public Domain | Page generated by Ddoc.


std.typetuple

Templates with which to manipulate type tuples (also known as type lists).

Some operations on type tuples are built in to the language, such as TL[n] which gets the nth type from the type tuple. TL[lwr .. upr] returns a new type list that is a slice of the old one.

References:
Based on ideas in Table 3.1 from Modern C++ Design, Andrei Alexandrescu (Addison-Wesley Professional, 2001)

Source:
std/typetuple.d

template TypeTuple(TList...)
Creates a typetuple out of a sequence of zero or more types.

Example:
 import std.typetuple;
 alias TypeTuple!(int, double) TL;

 int foo(TL td)  // same as int foo(int, double);
 {
    return td[0] + cast(int)td[1];
 }

Example:
 TypeTuple!(TL, char)
 // is equivalent to:
 TypeTuple!(int, double, char)

template IndexOf(T,TList...)
Returns the index of the first occurrence of type T in the sequence of zero or more types TList. If not found, -1 is returned.

Example:
 import std.typetuple;
 import std.stdio;

 void foo()
 {
    writefln("The index of long is ",
          IndexOf!(long, TypeTuple!(int, long, double)));
    // prints: The index of long is 1
 }

template Erase(T,TList...)
Returns a typetuple created from TList with the first occurrence, if any, of T removed.

Example:
 Erase!(long, int, long, double, char)
 // is the same as:
 TypeTuple!(int, double, char)

template EraseAll(T,TList...)
Returns a typetuple created from TList with the all occurrences, if any, of T removed.

Example:
 alias TypeTuple!(int, long, long, int) TL;

 EraseAll!(long, TL)
 // is the same as:
 TypeTuple!(int, int)

template NoDuplicates(TList...)
Returns a typetuple created from TList with the all duplicate types removed.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 NoDuplicates!(TL)
 // is the same as:
 TypeTuple!(int, long, float)

template Replace(T,U,TList...)
Returns a typetuple created from TList with the first occurrence of type T, if found, replaced with type U.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 Replace!(long, char, TL)
 // is the same as:
 TypeTuple!(int, char, long, int, float)

template ReplaceAll(T,U,TList...)
Returns a typetuple created from TList with all occurrences of type T, if found, replaced with type U.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 ReplaceAll!(long, char, TL)
 // is the same as:
 TypeTuple!(int, char, char, int, float)

template Reverse(TList...)
Returns a typetuple created from TList with the order reversed.

Example:
 alias TypeTuple!(int, long, long, int, float) TL;

 Reverse!(TL)
 // is the same as:
 TypeTuple!(float, int, long, long, int)

template MostDerived(T,TList...)
Returns the type from TList that is the most derived from type T. If none are found, T is returned.

Example:
 class A { }
 class B : A { }
 class C : B { }
 alias TypeTuple!(A, C, B) TL;

 MostDerived!(Object, TL) x;  // x is declared as type C

template DerivedToFront(TList...)
Returns the typetuple TList with the types sorted so that the most derived types come first.

Example:
 class A { }
 class B : A { }
 class C : B { }
 alias TypeTuple!(A, C, B) TL;

 DerivedToFront!(TL)
 // is the same as:
 TypeTuple!(C, B, A)

Public Domain | Page generated by Ddoc.


std.uni

Simple Unicode character classification functions. For ASCII classification, see std.ctype.

Source:
std/uni.d

References:
ASCII Table, Wikipedia, The Unicode Consortium

Trademarks:
Unicode(tm) is a trademark of Unicode, Inc.

int isUniLower(dchar c);
Returns !=0 if c is a Unicode lower case character.

int isUniUpper(dchar c);
Returns !=0 if c is a Unicode upper case character.

dchar toUniLower(dchar c);
If c is a Unicode upper case character, return the lower case equivalent, otherwise return c.

dchar toUniUpper(dchar c);
If c is a Unicode lower case character, return the upper case equivalent, otherwise return c.

int isUniAlpha(dchar u);
Return !=0 if u is a Unicode alpha character. (general Unicode category: Lu, Ll, Lt, Lm and Lo)

Standards:
Unicode 5.0.0

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.uri

Encode and decode Uniform Resource Identifiers (URIs). URIs are used in internet transfer protocols. Valid URI characters consist of letters, digits, and the characters ;/?:@&=+$,-.!~*'() Reserved URI characters are ;/?:@&=+$, Escape sequences consist of % followed by two hex digits.

See Also:
RFC 3986
Wikipedia

Source:
std/uri.d

char[] decode(char[] encodedURI);
Decodes the URI string encodedURI into a UTF-8 string and returns it. Escape sequences that resolve to reserved URI characters are not replaced. Escape sequences that resolve to the '#' character are not replaced.

char[] decodeComponent(char[] encodedURIComponent);
Decodes the URI string encodedURI into a UTF-8 string and returns it. All escape sequences are decoded.

char[] encode(char[] uri);
Encodes the UTF-8 string uri into a URI and returns that URI. Any character not a valid URI character is escaped. The '#' character is not escaped.

char[] encodeComponent(char[] uriComponent);
Encodes the UTF-8 string uriComponent into a URI and returns that URI. Any character not a letter, digit, or one of -.!~*'() is escaped.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.utf

Encode and decode UTF-8, UTF-16 and UTF-32 strings.

For Windows systems, the C wchar_t type is UTF-16 and corresponds to the D wchar type. For linux systems, the C wchar_t type is UTF-32 and corresponds to the D utf.dchar type.

UTF character support is restricted to (\u0000 <= character <= \U0010FFFF).

See Also:
Wikipedia
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335

Source:
std/utf.d

class UtfException: object.Exception;
Exception class that is thrown upon any errors.

size_t idx;
index in string of where error occurred

bool isValidDchar(dchar c);
Test if c is a valid UTF-32 character.

\uFFFE and \uFFFF are considered valid by this function, as they are permitted for internal use by an application, but they are not allowed for interchange by the Unicode standard.

Returns:
true if it is, false if not.

uint stride(char[] s, size_t i);
stride() returns the length of a UTF-8 sequence starting at index i in string s.

Returns:
The number of bytes in the UTF-8 sequence or 0xFF meaning s[i] is not the start of of UTF-8 sequence.

uint stride(wchar[] s, size_t i);
stride() returns the length of a UTF-16 sequence starting at index i in string s.

uint stride(dchar[] s, size_t i);
stride() returns the length of a UTF-32 sequence starting at index i in string s.

Returns:
The return value will always be 1.

size_t toUCSindex(char[] s, size_t i);
size_t toUCSindex(wchar[] s, size_t i);
size_t toUCSindex(dchar[] s, size_t i);
Given an index i into an array of characters s[], and assuming that index i is at the start of a UTF character, determine the number of UCS characters up to that index i.

size_t toUTFindex(char[] s, size_t n);
size_t toUTFindex(wchar[] s, size_t n);
size_t toUTFindex(dchar[] s, size_t n);
Given a UCS index n into an array of characters s[], return the UTF index.

dchar decode(char[] s, ref size_t idx);
dchar decode(wchar[] s, ref size_t idx);
dchar decode(dchar[] s, ref size_t idx);
Decodes and returns character starting at s[idx]. idx is advanced past the decoded character. If the character is not well formed, a UtfException is thrown and idx remains unchanged.

void encode(ref char[] s, dchar c);
void encode(ref wchar[] s, dchar c);
void encode(ref dchar[] s, dchar c);
Encodes character c and appends it to array s[].

void validate(char[] s);
void validate(wchar[] s);
void validate(dchar[] s);
Checks to see if string is well formed or not. Throws a UtfException if it is not. Use to check all untrusted input for correctness.

char[] toUTF8(char[] s);
char[] toUTF8(wchar[] s);
char[] toUTF8(dchar[] s);
Encodes string s into UTF-8 and returns the encoded string.

wchar[] toUTF16(char[] s);
wchar* toUTF16z(char[] s);
wchar[] toUTF16(wchar[] s);
wchar[] toUTF16(dchar[] s);
Encodes string s into UTF-16 and returns the encoded string. toUTF16z() is suitable for calling the 'W' functions in the Windows API that take an LPWSTR or LPCWSTR argument.

dchar[] toUTF32(char[] s);
dchar[] toUTF32(wchar[] s);
dchar[] toUTF32(dchar[] s);
Encodes string s into UTF-32 and returns the encoded string.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.zip

Read/write data in the zip archive format. Makes use of the etc.c.zlib compression library.

BUGS:
  • Multi-disk zips not supported.
  • Only Zip version 20 formats are supported.
  • Only supports compression modes 0 (no compression) and 8 (deflate).
  • Does not support encryption.
  • Bugzilla 592
  • Bugzilla 1832
  • Bugzilla 2137
  • Bugzilla 2138

Source:
std/zip.d

class ZipException: object.Exception;
Thrown on error.

class ArchiveMember;
A member of the ZipArchive.

ushort madeVersion;
Read Only

ushort extractVersion;
Read Only

ushort flags;
Read/Write: normally set to 0

ushort compressionMethod;
Read/Write: 0 for compression, 8 for deflate

std.date.DosFileTime time;
Read/Write: Last modified time of the member. It's in the DOS date/time format.

uint crc32;
Read Only: cyclic redundancy check (CRC) value

size_t compressedSize;
Read Only: size of data of member in compressed form.

size_t expandedSize;
Read Only: size of data of member in expanded form.

ushort diskNumber;
Read Only: should be 0.

ushort internalAttributes;
Read/Write

uint externalAttributes;
Read/Write

string name;
Read/Write: Usually the file name of the archive member; it is used to index the archive directory for the member. Each member must have a unique name[]. Do not change without removing member from the directory first.

ubyte[] extra;
Read/Write: extra data for this member.

string comment;
Read/Write: comment associated with this member.

ubyte[] compressedData;
Read Only: data of member in compressed form.

ubyte[] expandedData;
Read/Write: data of member in uncompressed form.

class ZipArchive;
Object representing the entire archive. ZipArchives are collections of ArchiveMembers.

ubyte[] data;
Read Only: array representing the entire contents of the archive.

uint diskNumber;
Read Only: 0 since multi-disk zip archives are not supported.

uint diskStartDir;
Read Only: 0 since multi-disk zip archives are not supported.

uint numEntries;
Read Only: number of ArchiveMembers in the directory.

uint totalEntries;
Read Only: same as totalEntries.

string comment;
Read/Write: the archive comment. Must be less than 65536 bytes in length.

ArchiveMember[char[]] directory;
Read Only: array indexed by the name of each member of the archive.

Example:
All the members of the archive can be accessed with a foreach loop:
 ZipArchive archive = new ZipArchive(data);
 foreach (ArchiveMember am; archive.directory)
 {
     writefln("member name is '%s'", am.name);
 }

this();
Constructor to use when creating a new archive.

void addMember(ArchiveMember de);
Add de to the archive.

void deleteMember(ArchiveMember de);
Delete de from the archive.

void[] build();
Construct an archive out of the current members of the archive.

Fills in the properties data[], diskNumber, diskStartDir, numEntries, totalEntries, and directory[]. For each ArchiveMember, fills in properties crc32, compressedSize, compressedData[].

Returns:
array representing the entire archive.

this(void[] buffer);
Constructor to use when reading an existing archive.

Fills in the properties data[], diskNumber, diskStartDir, numEntries, totalEntries, comment[], and directory[]. For each ArchiveMember, fills in properties madeVersion, extractVersion, flags, compressionMethod, time, crc32, compressedSize, expandedSize, compressedData[], diskNumber, internalAttributes, externalAttributes, name[], extra[], comment[]. Use expand() to get the expanded data for each ArchiveMember.

Params:
void[] buffer the entire contents of the archive.

ubyte[] expand(ArchiveMember de);
Decompress the contents of archive member de and return the expanded data.

Fills in properties extractVersion, flags, compressionMethod, time, crc32, compressedSize, expandedSize, expandedData[], name[], extra[].

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.zlib

Compress/decompress data using the zlib library.

References:
Wikipedia

License:
Public Domain

Source:
std/zlib.d

class ZlibException: object.Exception;
Errors throw a ZlibException.

uint adler32(uint adler, void[] buf);
Compute the Adler32 checksum of the data in buf[]. adler is the starting value when computing a cumulative checksum.

uint crc32(uint crc, void[] buf);
Compute the CRC32 checksum of the data in buf[]. crc is the starting value when computing a cumulative checksum.

void[] compress(void[] srcbuf, int level);
void[] compress(void[] buf);
Compresses the data in srcbuf[] using compression level level. The default value for level is 6, legal values are 1..9, with 1 being the least compression and 9 being the most. Returns the compressed data.

void[] uncompress(void[] srcbuf, size_t destlen = 0u, int winbits = 15);
Decompresses the data in srcbuf[].

Params:
size_t destlen size of the uncompressed data. It need not be accurate, but the decompression will be faster if the exact size is supplied.

Returns:
the decompressed data.

class Compress;
Used when the data to be compressed is not all in one buffer.

this(int level);
this();
Construct. level is the same as for D.zlib.compress().

void[] compress(void[] buf);
Compress the data in buf and return the compressed data. The buffers returned from successive calls to this should be concatenated together.

void[] flush(int mode = Z_FINISH);
Compress and return any remaining data. The returned data should be appended to that returned by compress().

Params:
int mode one of the following:
Z_SYNC_FLUSH
Syncs up flushing to the next byte boundary. Used when more data is to be compressed later on.
Z_FULL_FLUSH
Syncs up flushing to the next byte boundary. Used when more data is to be compressed later on, and the decompressor needs to be restartable at this point.
Z_FINISH
(default) Used when finished compressing the data.

class UnCompress;
Used when the data to be decompressed is not all in one buffer.

this(uint destbufsize);
this();
Construct. destbufsize is the same as for D.zlib.uncompress().

void[] uncompress(void[] buf);
Decompress the data in buf and return the decompressed data. The buffers returned from successive calls to this should be concatenated together.

void[] flush();
Decompress and return any remaining data. The returned data should be appended to that returned by uncompress(). The UnCompress object cannot be used further.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.fenv

C's <fenv.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

struct fenv_t;
Entire floating point environment

fenv_t* FE_DFL_ENV;
Default floating point environment

alias fexcept_t;
Floating point status flags

int fetestexcept(int excepts);

int feraiseexcept(int excepts);

int feclearexcept(int excepts);

int fegetround();

int fesetround(int round);

int fegetprec();

int fesetprec(int prec);

int fegetenv(fenv_t* envp);

int fesetenv(fenv_t* envp);

int fegetexceptflag(int* flagp, int excepts);

int fesetexceptflag(int* flagp, int excepts);

int feholdexcept(fenv_t* envp);

int feupdateenv(fenv_t* envp);

FE_INVALID

FE_DENORMAL

FE_DIVBYZERO

FE_OVERFLOW

FE_UNDERFLOW

FE_INEXACT

FE_ALL_EXCEPT
Mask of all the exceptions

FE_TONEAREST

FE_UPWARD

FE_DOWNWARD

FE_TOWARDZERO

FE_FLTPREC

FE_DBLPREC

FE_LDBLPREC

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.locale

C's <locale.h>

License:
Public Domain

Standards:
ISO/IEC 9899:1999 7.11

struct lconv;
Structure giving information about numeric and monetary notation.

char* decimal_point;
The decimal-point character used to format nonmonetary quantities.

char* thousands_sep;
The character used to separate groups of digits before the decimal-point character in formatted nonmonetary quantities.

char* grouping;
A string whose elements indicate the size of each group of digits in formatted nonmonetary quantities.

char* int_curr_symbol;
The international currency symbol applicable to the current locale. The first three characters contain the alphabetic international currency symbol in accordance with those specified in ISO 4217. The fourth character (immediately preceding the null character) is the character used to separate the international currency symbol from the monetary quantity.

char* currency_symbol;
The local currency symbol applicable to the current locale.

char* mon_decimal_point;
The decimal-point used to format monetary quantities.

char* mon_thousands_sep;
The separator for groups of digits before the decimal-point in formatted monetary quantities.

char* mon_grouping;
A string whose elements indicate the size of each group of digits in formatted monetary quantities.

char* positive_sign;
The string used to indicate a nonnegative-valued formatted monetary quantity.

char* negative_sign;
The string used to indicate a negative-valued formatted monetary quantity.

char int_frac_digits;
The number of fractional digits (those after the decimal-point) to be displayed in an internationally formatted monetary quantity.

char frac_digits;
The number of fractional digits (those after the decimal-point) to be displayed in a locally formatted monetary quantity.

char p_cs_precedes;
1 if currency_symbol precedes a positive value, 0 if succeeds.

char p_sep_by_space;
1 if a space separates currency_symbol from a positive value.

char n_cs_precedes;
1 if currency_symbol precedes a negative value, 0 if succeeds.

char n_sep_by_space;
1 if a space separates currency_symbol from a negative value.

char int_p_cs_precedes;
1 if int_curr_symbol precedes a positive value, 0 if succeeds.

char int_p_sep_by_space;
1 iff a space separates int_curr_symbol from a positive value.

char int_n_cs_precedes;
1 if int_curr_symbol precedes a negative value, 0 if succeeds.

char int_n_sep_by_space;
1 iff a space separates int_curr_symbol from a negative value.

const int LC_CTYPE;
Affects the behavior of C's character handling functions and C's multibyte and wide character functions.

const int LC_NUMERIC;
Affects the decimal-point character for C's formatted input/output functions and C's string conversion functions, as well as C's nonmonetary formatting information returned by the localeconv function.

const int LC_TIME;
Affects the behavior of the strftime and wcsftime functions.

const int LC_COLLATE;
Affects the behavior of the strcoll and strxfrm functions.

const int LC_MONETARY;
Affects the monetary formatting information returned by the localeconv function.

const int LC_ALL;
The program's entire locale.

char* setlocale(int category, char* locale);
The setlocale function selects the appropriate portion of the program's locale as specified by the category and locale arguments.

lconv* localeconv();
The localeconv function sets the components of an object with type lconv with values appropriate for the formatting of numeric quantities (monetary and otherwise) according to the rules of the current locale.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.math

C's <math.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

alias float_t;

alias double_t;

const double HUGE_VAL;
const float HUGE_VALF;
const real HUGE_VALL;

const float INFINITY;

const float NAN;

FP_INFINITE

FP_NAN

FP_NORMAL

FP_SUBNORMAL

FP_ZERO

FP_FAST_FMA

FP_FAST_FMAF

FP_FAST_FMAL

const int FP_ILOGB0;

const int FP_ILOGBNAN;

const int MATH_ERRNO;

const int MATH_ERREXCEPT;

const int math_errhandling;

double acos(double x);
float acosf(float x);
real acosl(real x);

double asin(double x);
float asinf(float x);
real asinl(real x);

double atan(double x);
float atanf(float x);
real atanl(real x);

double atan2(double y, double x);
float atan2f(float y, float x);
real atan2l(real y, real x);

double cos(double x);
float cosf(float x);
real cosl(real x);

double sin(double x);
float sinf(float x);
real sinl(real x);

double tan(double x);
float tanf(float x);
real tanl(real x);

double acosh(double x);
float acoshf(float x);
real acoshl(real x);

double asinh(double x);
float asinhf(float x);
real asinhl(real x);

double atanh(double x);
float atanhf(float x);
real atanhl(real x);

double cosh(double x);
float coshf(float x);
real coshl(real x);

double sinh(double x);
float sinhf(float x);
real sinhl(real x);

double tanh(double x);
float tanhf(float x);
real tanhl(real x);

double exp(double x);
float expf(float x);
real expl(real x);

double exp2(double x);
float exp2f(float x);
real exp2l(real x);

double expm1(double x);
float expm1f(float x);
real expm1l(real x);

double frexp(double value, int* exp);
float frexpf(float value, int* exp);
real frexpl(real value, int* exp);

int ilogb(double x);
int ilogbf(float x);
int ilogbl(real x);

double ldexp(double x, int exp);
float ldexpf(float x, int exp);
real ldexpl(real x, int exp);

double log(double x);
float logf(float x);
real logl(real x);

double log10(double x);
float log10f(float x);
real log10l(real x);

double log1p(double x);
float log1pf(float x);
real log1pl(real x);

double log2(double x);
float log2f(float x);
real log2l(real x);

double logb(double x);
float logbf(float x);
real logbl(real x);

double modf(double value, double* iptr);
float modff(float value, float* iptr);
real modfl(real value, real* iptr);

double scalbn(double x, int n);
float scalbnf(float x, int n);
real scalbnl(real x, int n);

double scalbln(double x, int n);
float scalblnf(float x, int n);
real scalblnl(real x, int n);

double cbrt(double x);
float cbrtf(float x);
real cbrtl(real x);

double fabs(double x);
float fabsf(float x);
real fabsl(real x);

double hypot(double x, double y);
float hypotf(float x, float y);
real hypotl(real x, real y);

double pow(double x, double y);
float powf(float x, float y);
real powl(real x, real y);

double sqrt(double x);
float sqrtf(float x);
real sqrtl(real x);

double erf(double x);
float erff(float x);
real erfl(real x);

double erfc(double x);
float erfcf(float x);
real erfcl(real x);

double lgamma(double x);
float lgammaf(float x);
real lgammal(real x);

double tgamma(double x);
float tgammaf(float x);
real tgammal(real x);

double ceil(double x);
float ceilf(float x);
real ceill(real x);

double floor(double x);
float floorf(float x);
real floorl(real x);

double nearbyint(double x);
float nearbyintf(float x);
real nearbyintl(real x);

double rint(double x);
float rintf(float x);
real rintl(real x);

int lrint(double x);
int lrintf(float x);
int lrintl(real x);

long llrint(double x);
long llrintf(float x);
long llrintl(real x);

double round(double x);
float roundf(float x);
real roundl(real x);

int lround(double x);
int lroundf(float x);
int lroundl(real x);

long llround(double x);
long llroundf(float x);
long llroundl(real x);

double trunc(double x);
float truncf(float x);
real truncl(real x);

double fmod(double x, double y);
float fmodf(float x, float y);
real fmodl(real x, real y);

double remainder(double x, double y);
float remainderf(float x, float y);
real remainderl(real x, real y);

double remquo(double x, double y, int* quo);
float remquof(float x, float y, int* quo);
real remquol(real x, real y, int* quo);

double copysign(double x, double y);
float copysignf(float x, float y);
real copysignl(real x, real y);

double nan(char* tagp);
float nanf(char* tagp);
real nanl(char* tagp);

double nextafter(double x, double y);
float nextafterf(float x, float y);
real nextafterl(real x, real y);

double nexttoward(double x, real y);
float nexttowardf(float x, real y);
real nexttowardl(real x, real y);

double fdim(double x, double y);
float fdimf(float x, float y);
real fdiml(real x, real y);

double fmax(double x, double y);
float fmaxf(float x, float y);
real fmaxl(real x, real y);

double fmin(double x, double y);
float fminf(float x, float y);
real fminl(real x, real y);

double fma(double x, double y, double z);
float fmaf(float x, float y, float z);
real fmal(real x, real y, real z);

int isgreater(real x, real y);

int isgreaterequal(real x, real y);

int isless(real x, real y);

int islessequal(real x, real y);

int islessgreater(real x, real y);

int isunordered(real x, real y);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.process

C's <process.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.stdarg

C's <stdarg.h> This is for use with extern(C) variable argument lists.

Authors:
Hauke Duden and Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Source:
std/c/stdarg.d

alias va_list;
The argument pointer type.

void va_start(T)(out va_list ap, ref T parmn);
Initialize ap. For 32 bit code, parmn should be the last named parameter. For 64 bit code, parmn should be _va_argsave.

T va_arg(T)(ref va_list ap);
Retrieve and return the next value that is type T. Should use the other va_arg instead, as this won't work for 64 bit code.

void va_arg(T)(ref va_list ap, ref T parmn);
Retrieve and return the next value that is type T. This is the preferred version.

void va_arg()(ref va_list ap, TypeInfo ti, void* parmn);
Retrieve and store through parmn the next value that is of TypeInfo ti. Used when the static type is not known.

void va_end(va_list ap);
End use of ap.

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.stddef

C's <stddef.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.stdio

C's <stdio.h> for the D programming language

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Source:
std/c/stdio.d

const int _NFILE;

const int BUFSIZ;

const int EOF;

const int FOPEN_MAX;

const int FILENAME_MAX;
255 plus NULL

const int TMP_MAX;

const int _SYS_OPEN;

const int SYS_OPEN;

const wchar WEOF;

alias FILE;

const _iobuf* stdin;

const _iobuf* stdout;

const _iobuf* stderr;

const _iobuf* stdaux;

const _iobuf* stdprn;

alias fpos_t;

int ferror(_iobuf* fp);

int feof(_iobuf* fp);

void clearerr(_iobuf* fp);

void rewind(_iobuf* fp);

int fileno(_iobuf* fp);

int fwide(_iobuf* fp, int mode);

char* tmpnam(char*);

_iobuf* fopen(char*, char*);

_iobuf* _fsopen(char*, char*, int);

_iobuf* freopen(char*, char*, _iobuf*);

int fseek(_iobuf*, int, int);

int ftell(_iobuf*);

char* fgets(char*, int, _iobuf*);

int fgetc(_iobuf*);

int _fgetchar();

int fflush(_iobuf*);

int fclose(_iobuf*);

int fputs(char*, _iobuf*);

char* gets(char*);

int fputc(int, _iobuf*);

int _fputchar(int);

int puts(char*);

int ungetc(int, _iobuf*);

size_t fread(void*, size_t, size_t, _iobuf*);

size_t fwrite(void*, size_t, size_t, _iobuf*);

int fprintf(_iobuf*, char*, ...);

int vfprintf(_iobuf*, char*, va_list);

int vprintf(char*, va_list);

int sprintf(char*, char*, ...);

int vsprintf(char*, char*, va_list);

int scanf(char*, ...);

int fscanf(_iobuf*, char*, ...);

int sscanf(char*, char*, ...);

void setbuf(_iobuf*, char*);

int setvbuf(_iobuf*, char*, int, size_t);

int remove(char*);

int rename(char*, char*);

void perror(char*);

int fgetpos(_iobuf*, int*);

int fsetpos(_iobuf*, int*);

_iobuf* tmpfile();

int getw(_iobuf* FHdl);

int putw(int Word, _iobuf* FilePtr);

int getchar();

int putchar(int c);

int getc(_iobuf* fp);

int putc(int c, _iobuf* fp);

int unlink(char*);

_iobuf* fdopen(int, char*);

int fgetchar();

int fputchar(int);

int fcloseall();

int filesize(char*);

int flushall();

int getch();

int getche();

int kbhit();

char* tempnam(char* dir, char* pfx);

wchar* _wtmpnam(wchar*);

wchar* fgetws(wchar*, int, _iobuf*);

int fputws(wchar*, _iobuf*);

int wprintf(wchar*, ...);

int fwprintf(_iobuf*, wchar*, ...);

int vwprintf(wchar*, va_list);

int vfwprintf(_iobuf*, wchar*, va_list);

int swprintf(wchar*, wchar*, ...);

int vswprintf(wchar*, wchar*, va_list);

int wscanf(wchar*, ...);

int fwscanf(_iobuf*, wchar*, ...);

int swscanf(wchar*, wchar*, ...);

wchar_t fgetwc(_iobuf*);

wchar_t fputwc(wchar_t, _iobuf*);

wchar_t ungetwc(wchar_t, _iobuf*);

wchar_t getwchar_t();

wchar_t putwchar_t(wchar_t c);

wchar_t getwc(_iobuf* fp);

wchar_t putwc(wchar_t c, _iobuf* fp);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.stdlib

C's <stdlib.h> D Programming Language runtime library

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

struct div_t;

struct ldiv_t;

struct lldiv_t;

div_t div(int, int);
ldiv_t ldiv(int, int);
lldiv_t lldiv(long, long);

const int EXIT_SUCCESS;
const int EXIT_FAILURE;

int atexit(void function());
void exit(int);
void _exit(int);

void* alloca(size_t);
Allocate bytes on stack

void* calloc(size_t, size_t);
void* malloc(size_t);
void* realloc(void*, size_t);
void free(void*);

void* bsearch(void*, void*, size_t, size_t, int function(void*, void*));
void qsort(void* base, size_t nelems, size_t elemsize, int function(void* elem1, void* elem2) compare);

char* getenv(char*);

int setenv(char*, char*, int);
extension to ISO C standard, not available on all platforms

void unsetenv(char*);
extension to ISO C standard, not available on all platforms

int rand();
void srand(uint);
int random(int num);
void randomize();
int getErrno();
int setErrno(int);

double atof(char*);
int atoi(char*);
int atol(char*);
float strtof(char*, char**);
double strtod(char*, char**);
real strtold(char*, char**);
long strtol(char*, char**, int);
uint strtoul(char*, char**, int);
long atoll(char*);
long strtoll(char*, char**, int);
ulong strtoull(char*, char**, int);

char* itoa(int, char*, int);
char* ultoa(uint, char*, int);

int mblen(char* s, size_t n);
int mbtowc(wchar* pwc, char* s, size_t n);
int wctomb(char* s, wchar_t wc);
size_t mbstowcs(wchar* pwcs, char* s, size_t n);
size_t wcstombs(char* s, wchar* pwcs, size_t n);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.string

C's <string.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

void* memcpy(void* s1, void* s2, size_t n);

void* memmove(void* s1, void* s2, size_t n);

char* strcpy(char* s1, char* s2);

char* strncpy(char* s1, char* s2, size_t n);

char* strncat(char* s1, char* s2, size_t n);

int strcoll(char* s1, char* s2);

int strncmp(char* s1, char* s2, size_t n);

size_t strxfrm(char* s1, char* s2, size_t n);

void* memchr(void* s, int c, size_t n);

char* strchr(char* s, int c);

size_t strcspn(char* s1, char* s2);

char* strpbrk(char* s1, char* s2);

char* strrchr(char* s, int c);

size_t strspn(char* s1, char* s2);

char* strstr(char* s1, char* s2);

char* strtok(char* s1, char* s2);

void* memset(void* s, int c, size_t n);

char* strerror(int errnum);

size_t strlen(char* s);

int strcmp(char* s1, char* s2);

char* strcat(char* s1, char* s2);

int memcmp(void* s1, void* s2, size_t n);

int memicmp(char* s1, char* s2, size_t n);

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.time

C's <time.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.wcharh

C's <wchar.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.windows.charset

Support UTF-8 on Windows 95, 98 and ME systems.

char* toMBSz(char[] s, uint codePage = 0);
Converts the UTF-8 string s into a null-terminated string in a Windows 8-bit character set.

Params:
char[] s | UTF-8 string to convert.
uint codePage | is the number of the target codepage, or 0 - ANSI, 1 - OEM, 2 - Mac

Authors:
yaneurao, Walter Bright, Stewart Gordon

char[] fromMBSz(char* s, int codePage = 0);
Converts the null-terminated string s from a Windows 8-bit character set into a UTF-8 char array.

Params:
char* s | UTF-8 string to convert.
int codePage | is the number of the source codepage, or 0 - ANSI, 1 - OEM, 2 - Mac

Authors:
Stewart Gordon, Walter Bright

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


Comparison

Last update Sun Dec 30 20:34:43 2012

vs Other Languages

To D, or not to D. -- Willeam NerdSpeare

This table is a quick and rough list of various features of that can be used to compare with other languages. While many capabilities are available with standard libraries, this table is for features built in to the core language itself. Rationale.

D Language Feature Comparison Table
Feature |
Garbage Collection | Yes
Functions
Function delegates | Yes
Function overloading | Yes
Out function parameters | Yes
Nested functions | Yes
Function literals | Yes
Dynamic closures | Yes
Typesafe variadic arguments | Yes
Lazy function argument evaluation | Yes
Compile time function evaluation | Yes
Arrays
Lightweight arrays | Yes
Resizeable arrays | Yes
Built-in strings | Yes
Array slicing | Yes
Array bounds checking | Yes
Array literals | Yes
Associative arrays | Yes
Strong typedefs | Yes
String switches | Yes
Aliases | Yes
OOP
Object Oriented | Yes
Multiple Inheritance | No
Interfaces | Yes
Operator overloading | Yes
Modules | Yes
Dynamic class loading | No
Nested classes | Yes
Inner (adaptor) classes | Yes
Covariant return types | Yes
Properties | Yes
Performance
Inline assembler | Yes
Direct access to hardware | Yes
Lightweight objects | Yes
Explicit memory allocation control | Yes
Independent of VM | Yes
Direct native code gen | Yes
Generic Programming
Class Templates | Yes
Function Templates | Yes
Implicit Function Template Instantiation | Yes
Partial and Explicit Specialization | Yes
Value Template Parameters | Yes
Template Template Parameters | Yes
Variadic Template Parameters | Yes
Mixins | Yes
static if | Yes
is expressions | Yes
typeof | Yes
foreach | Yes
Implicit Type Inference | Yes
Reliability
Contract Programming | Yes
Unit testing | Yes
Static construction order | Yes
Guaranteed initialization | Yes
RAII (automatic destructors) | Yes
Exception handling | Yes
Scope guards | Yes
try-catch-finally blocks | Yes
Thread synchronization primitives | Yes
Compatibility
C-style syntax | Yes
Enumerated types | Yes
Support all C types | Yes
80 bit floating point | Yes
Complex and Imaginary | Yes
Direct access to C | Yes
Use existing debuggers | Yes
Struct member alignment control | Yes
Generates standard object files | Yes
Macro text preprocessor | No
Other
Conditional compilation | Yes
Unicode source text | Yes
Documentation comments | Yes

Notes

Object Oriented
This means support for classes, member functions, inheritance, and virtual function dispatch.

Inline assembler
Many C and C++ compilers support an inline assembler, but this is not a standard part of the language, and implementations vary widely in syntax and quality.

Interfaces
Support in C++ for interfaces is weak enough that an IDL (Interface Description Language) was invented to compensate.

Modules
Many correctly argue that C++ doesn't really have modules. But C++ namespaces coupled with header files share many features with modules.

Garbage Collection
The Hans-Boehm garbage collector can be successfully used with C and C++, but it is not a standard part of the language.

Implicit Type Inference
This refers to the ability to pick up the type of a declaration from its initializer.

Contract Programming
The Digital Mars C++ compiler supports Contract Programming as an extension. Compare some C++ techniques for doing Contract Programming with D.

Resizeable arrays
Part of the standard library for C++ implements resizeable arrays, however, they are not part of the core language. A conforming freestanding implementation of C++ (C++98 17.4.1.3) does not need to provide these libraries.

Built-in Strings
Part of the standard library for C++ implements strings, however, they are not part of the core language. A conforming freestanding implementation of C++ (C++98 17.4.1.3) does not need to provide these libraries. Here's a comparison of C++ strings and D built-in strings.

Strong typedefs
Strong typedefs can be emulated in C/C++ by wrapping a type in a struct. Getting this to work right requires much tedious programming, and so is considered as not supported.

Use existing debuggers
By this is meant using common debuggers that can operate using debug data in common formats embedded in the executable. A specialized debugger useful only with that language is not required.

Struct member alignment control
Although many C/C++ compilers contain pragmas to specify struct alignment, these are nonstandard and incompatible from compiler to compiler.
The C# standard ECMA-334 25.5.8 says only this about struct member alignment: "The order in which members are packed into a struct is unspecified. For alignment purposes, there may be unnamed padding at the beginning of a struct, within a struct, and at the end of the struct. The contents of the bits used as padding are indeterminate." Therefore, although Microsoft may have extensions to support specific member alignment, they are not an official part of standard C#.

Support all C types
C99 adds many new types not supported by C++.

80 bit floating point
While the standards for C and C++ specify long doubles, few compilers (besides Digital Mars C/C++) actually implement 80 bit (or longer) floating point types.

Mixins
Mixins have many different meanings in different programming languages. D mixins mean taking an arbitrary sequence of declarations and inserting (mixing) them into the current scope. Mixins can be done at the global, class, struct, or local level.

C++ Mixins
C++ mixins refer to a couple different techniques. The first is analogous to D's interface classes. The second is to create a template of the form:
template <class Base> class Mixin : public Base
{
    ... mixin body ...
}
D mixins are different.

Static If
The C and C++ preprocessor directive #if would appear to be equivalent to the D static if. But there are major and crucial differences - the #if does not have access to any of the constants, types, or symbols of the program. It can only access preprocessor macros. See this example.

Is Expressions
Is expressions enable conditional compilation based on the characteristics of a type. This is done after a fashion in C++ using template parameter pattern matching. See this example for a comparison of the different approaches.

Comparison with Ada
James S. Rogers has written a comparison chart with Ada.

Inner (adaptor) classes
A nested class is one whose definition is within the scope of another class. An inner class is a nested class that can also reference the members and fields of the lexically enclosing class; one can think of it as if it contained a 'this' pointer to the enclosing class.

Documentation comments
Documentation comments refer to a standardized way to produce documentation from the source code file using specialized comments.

Errors

If I've made any errors in this table, please contact me so I can correct them.


D Builtin Rationale

Last update Sun Dec 30 20:34:43 2012

Core Language Features vs Library Implementation

D offers several capabilities built in to the core language that are implemented as libraries in other languages such as C++:

  1. Dynamic Arrays
  2. Strings
  3. Associative Arrays
  4. Complex numbers

Some consider this as evidence of language bloat, rather than a useful feature. So why not implement each of these as standardized library types?

Some general initial observations:

  1. Each of them is heavily used. This means that even small improvements in usability are worth reaching for.
  2. Being a core language feature means that the compiler can issue better and more to the point error messages when a type is used incorrectly. Library implementations tend to give notoriously obtuse messages based on the internal details of those implementations.
  3. Library features cannot invent new syntax, new operators, or new tokens.
  4. Library implementations tend to require a lot of compile time processing of the implementation, over and over for each compile, that slows down compilation.
  5. Library implementations are supposed to provide flexibility to the end user. But if they are standardized, standardized to the point of the compiler being allowed to recognized them as special (the C++ Standard allows this), then they become just as inflexible as builtin core features.
  6. The ability to define new library types, while having greatly advanced in the last few years, still leaves a lot to be desired in smoothly integrating it into the existing language. Rough edges, clumsy syntax, and odd corner cases abound.

More specific comments:

Dynamic Arrays

C++ has builtin core arrays. It's just that they don't work very well. Rather than fix them, several different array types were created as part of the C++ Standard Template Library, each covering a different deficiency in the builtin arrays. These include:

  • basic_string
  • vector
  • valarray
  • deque
  • slice_array
  • gslice_array
  • mask_array
  • indirect_array

Fixing the builtin array support means the need for each of these variations just evaporates. There's one array type that covers it all, only one thing to learn, and no problems getting one array type to work with another array type.

As usual, a builtin type lets us create syntactic sugar for it. This starts with having an array literal, and follows with some new operators specific to arrays. A library array implementation has to make due with overloading existing operators. The indexing operator, a[i], it shares with C++. Added are the array concatenation operator ~, array append operator ~=, array slice operator a[i..j], and the array vector operator a[].

The ~ and ~= concatenation operators resolve a problem that comes up when only existing operators can be overloaded. Usually, + is pressed into service as concatenation for library array implementations. But that winds up precluding having + mean array vector addition. Furthermore, concatenation has nothing in common with addition, and using the same operator for both is confusing.

Strings

A detailed comparison with C++'s std::string.

C++ has, of course, builtin string support in the form of string literals and char arrays. It's just that they suffer from all the weaknesses of C++ builtin arrays.

But after all, what is a string if not an array of characters? If the builtin array problems are fixed, doesn't that resolve the string problems as well? It does. It seems odd at first that D doesn't have a string class, but since manipulating strings is nothing more than manipulating arrays of characters, if arrays work, there's nothing a class adds to it.

Furthermore, the oddities resulting from builtin string literals not being of the same type as the library string class type go away.

Associative Arrays

The main benefit for this is, once again, syntactic sugar. An associative array keying off of a type T and storing an int value is naturally written as:

int[T] foo;

rather than:

import std.associativeArray;
...
std.associativeArray.AA!(T, int) foo;

Builtin associative arrays also offer the possibility of having associative array literals, which are an often requested additional feature.

Complex Numbers

A detailed comparison with C++'s std::complex.

The most compelling reason is compatibility with C's imaginary and complex floating point types. Next, is the ability to have imaginary floating point literals. Isn't:

c = (6 + 2i - 1 + 3i) / 3i;

far preferable than writing:

c = (complex!(double)(6,2) + complex!(double)(-1,3)) / complex!(double)(0,3);

? It's no contest.


Programming in D for C Programmers

Last update Sun Dec 30 20:34:42 2012

Programming in D for C Programmers

Et tu, D? Then fall, C! -- William Nerdspeare

ouch!

Every experienced C programmer accumulates a series of idioms and techniques which become second nature. Sometimes, when learning a new language, those idioms can be so comfortable it's hard to see how to do the equivalent in the new language. So here's a collection of common C techniques, and how to do the corresponding task in D.

Since C does not have object-oriented features, there's a separate section for object-oriented issues Programming in D for C++ Programmers.

The C preprocessor is covered in The C Preprocessor vs D.

  • Getting the Size of a Type
  • Get the max and min values of a type
  • Primitive Types
  • Special Floating Point Values
  • Remainder after division of floating point numbers
  • Dealing with NANs in floating point compares
  • Asserts
  • Initializing all elements of an array
  • Looping through an array
  • Creating an array of variable size
  • String Concatenation
  • Formatted printing
  • Forward referencing functions
  • Functions that have no arguments
  • Labeled break and continue statements
  • Goto Statements
  • Struct tag name space
  • Looking up strings
  • Setting struct member alignment
  • Anonymous Structs and Unions
  • Declaring struct types and variables
  • Getting the offset of a struct member
  • Union initializations
  • Struct initializations
  • Array initializations
  • Escaped String Literals
  • Ascii vs Wide Characters
  • Arrays that parallel an enum
  • Creating a new type with typedef
  • Comparing structs
  • Comparing strings
  • Sorting arrays
  • Volatile memory access
  • String literals
  • Data Structure Traversal
  • Unsigned Right Shift
  • Dynamic Closures
  • Variadic Function Parameters

Getting the Size of a Type

The C Way

sizeof(int)
sizeof(char *)
sizeof(double)
sizeof(struct Foo)

The D Way

Use the size property:

int.sizeof
(char *).sizeof
double.sizeof
Foo.sizeof

Get the max and min values of a type

The C Way

#include <limits.h>
#include <math.h>

CHAR_MAX
CHAR_MIN
ULONG_MAX
DBL_MIN

The D Way

char.max
char.min
ulong.max
double.min

Primitive Types

C to D types

bool               =>        bit
char               =>        char
signed char        =>        byte
unsigned char      =>        ubyte
short              =>        short
unsigned short     =>        ushort
wchar_t            =>        wchar
int                =>        int
unsigned           =>        uint
long               =>        int
unsigned long      =>        uint
long long          =>        long
unsigned long long =>        ulong
float              =>        float
double             =>        double
long double        =>        real
_Imaginary long double =>    ireal
_Complex long double   =>    creal

Although char is an unsigned 8 bit type, and wchar is an unsigned 16 bit type, they have their own separate types in order to aid overloading and type safety.

Ints and unsigneds in C are of varying size; not so in D.

Special Floating Point Values

The C Way

#include <fp.h>

NAN
INFINITY

#include <float.h>

DBL_DIG
DBL_EPSILON
DBL_MANT_DIG
DBL_MAX_10_EXP
DBL_MAX_EXP
DBL_MIN_10_EXP
DBL_MIN_EXP

The D Way

double.nan
double.infinity
double.dig
double.epsilon
double.mant_dig
double.max_10_exp
double.max_exp
double.min_10_exp
double.min_exp

Remainder after division of floating point numbers

The C Way

#include <math.h>

float f = fmodf(x,y);
double d = fmod(x,y);
long double r = fmodl(x,y);

The D Way

D supports the remainder ('%') operator on floating point operands:
float f = x % y;
double d = x % y;
real r = x % y;

Dealing with NANs in floating point compares

The C Way

C doesn't define what happens if an operand to a compare is NAN, and few C compilers check for it (the Digital Mars C compiler is an exception, DM's compilers do check for NAN operands).
#include <math.h>

if (isnan(x) || isnan(y))
   result = FALSE;
else
   result = (x < y);

The D Way

D offers a full complement of comparisons and operators that work with NAN arguments.
result = (x < y);        // false if x or y is nan

Asserts are a necessary part of any good defensive coding strategy

The C Way

C doesn't directly support assert, but does support __FILE__ and __LINE__ from which an assert macro can be built. In fact, there appears to be practically no other use for __FILE__ and __LINE__.

#include <assert.h>

assert(e == 0);

The D Way

D simply builds assert into the language:
assert(e == 0);

Initializing all elements of an array

The C Way

#define ARRAY_LENGTH        17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
   array[i] = value;

The D Way

int array[17];
array[] = value;

Looping through an array

The C Way

The array length is defined separately, or a clumsy sizeof() expression is used to get the length.

#define ARRAY_LENGTH        17
int array[ARRAY_LENGTH];
for (i = 0; i < ARRAY_LENGTH; i++)
   func(array[i]);
or:
int array[17];
for (i = 0; i < sizeof(array) / sizeof(array[0]); i++)
   func(array[i]);

The D Way

The length of an array is accessible through the property "length".
int array[17];
for (i = 0; i < array.length; i++)
   func(array[i]);
or even better:
int array[17];
foreach (int value; array)
   func(value);

Creating an array of variable size

The C Way

C cannot do this with arrays. It is necessary to create a separate variable for the length, and then explicitly manage the size of the array:
#include <stdlib.h>

int array_length;
int *array;
int *newarray;

newarray = (int *)
   realloc(array, (array_length + 1) * sizeof(int));
if (!newarray)
   error("out of memory");
array = newarray;
array[array_length++] = x;

The D Way

D supports dynamic arrays, which can be easily resized. D supports all the requisite memory management.
int[] array;

array.length = array.length + 1;
array[array.length - 1] = x;

String Concatenation

The C Way

There are several difficulties to be resolved, like when can storage be freed, dealing with null pointers, finding the length of the strings, and memory allocation:
#include <string.h>

char *s1;
char *s2;
char *s;

// Concatenate s1 and s2, and put result in s
free(s);
s = (char *)malloc((s1 ? strlen(s1) : 0) +
          (s2 ? strlen(s2) : 0) + 1);
if (!s)
   error("out of memory");
if (s1)
   strcpy(s, s1);
else
   *s = 0;
if (s2)
   strcpy(s + strlen(s), s2);

// Append "hello" to s
char hello[] = "hello";
char *news;
size_t lens = s ? strlen(s) : 0;
news = (char *)
   realloc(s, (lens + sizeof(hello) + 1) * sizeof(char));
if (!news)
   error("out of memory");
s = news;
memcpy(s + lens, hello, sizeof(hello));

The D Way

D overloads the operators ~ and ~= for char and wchar arrays to mean concatenate and append, respectively:
char[] s1;
char[] s2;
char[] s;

s = s1 ~ s2;
s ~= "hello";

Formatted printing

The C Way

printf() is the general purpose formatted print routine:
#include <stdio.h>

printf("Calling all cars %d times!\n", ntimes);

The D Way

What can we say? printf() rules:
printf("Calling all cars %d times!\n", ntimes);
writefln() improves on printf() by being type-aware and type-safe:
import std.stdio;

writefln("Calling all cars %s times!", ntimes);

Forward referencing functions

The C Way

Functions cannot be forward referenced. Hence, to call a function not yet encountered in the source file, it is necessary to insert a function declaration lexically preceding the call.
void forwardfunc();

void myfunc()
{
   forwardfunc();
}

void forwardfunc()
{
   ...
}

The D Way

The program is looked at as a whole, and so not only is it not necessary to code forward declarations, it is not even allowed! D avoids the tedium and errors associated with writing forward referenced function declarations twice. Functions can be defined in any order.
void myfunc()
{
   forwardfunc();
}

void forwardfunc()
{
   ...
}

Functions that have no arguments

The C Way

void function(void);

The D Way

D is a strongly typed language, so there is no need to explicitly say a function takes no arguments, just don't declare it has having arguments.
void function()
{
   ...
}

Labeled break and continue statements

The C Way

Break and continue statements only apply to the innermost nested loop or switch, so a multilevel break must use a goto:
    for (i = 0; i < 10; i++)
    {
       for (j = 0; j < 10; j++)
       {
       if (j == 3)
           goto Louter;
       if (j == 4)
           goto L2;
       }
     L2:
       ;
    }
Louter:
    ;

The D Way

Break and continue statements can be followed by a label. The label is the label for an enclosing loop or switch, and the break applies to that loop.
Louter:
   for (i = 0; i < 10; i++)
   {
       for (j = 0; j < 10; j++)
       {
       if (j == 3)
           break Louter;
       if (j == 4)
           continue Louter;
       }
   }
   // break Louter goes here

Goto Statements

The C Way

The much maligned goto statement is a staple for professional C coders. It's necessary to make up for sometimes inadequate control flow statements.

The D Way

Many C-way goto statements can be eliminated with the D feature of labeled break and continue statements. But D is a practical language for practical programmers who know when the rules need to be broken. So of course D supports goto statements.

Struct tag name space

The C Way

It's annoying to have to put the struct keyword every time a type is specified, so a common idiom is to use:
typedef struct ABC { ... } ABC;

The D Way

Struct tag names are not in a separate name space, they are in the same name space as ordinary names. Hence:
struct ABC { ... }

Looking up strings

The C Way

Given a string, compare the string against a list of possible values and take action based on which one it is. A typical use for this might be command line argument processing.
#include <string.h>
void dostring(char *s)
{
   enum Strings { Hello, Goodbye, Maybe, Max };
   static char *table[] = { "hello", "goodbye", "maybe" };
   int i;

   for (i = 0; i < Max; i++)
   {
       if (strcmp(s, table[i]) == 0)
       break;
   }
   switch (i)
   {
       case Hello:   ...
       case Goodbye: ...
       case Maybe:   ...
       default:      ...
   }
}
The problem with this is trying to maintain 3 parallel data structures, the enum, the table, and the switch cases. If there are a lot of values, the connection between the 3 may not be so obvious when doing maintenance, and so the situation is ripe for bugs. Additionally, if the number of values becomes large, a binary or hash lookup will yield a considerable performance increase over a simple linear search. But coding these can be time consuming, and they need to be debugged. It's typical that such just never gets done.

The D Way

D extends the concept of switch statements to be able to handle strings as well as numbers. Then, the way to code the string lookup becomes straightforward:
void dostring(char[] s)
{
   switch (s)
   {
       case "hello":   ...
       case "goodbye": ...
       case "maybe":   ...
       default:        ...
   }
}
Adding new cases becomes easy. The compiler can be relied on to generate a fast lookup scheme for it, eliminating the bugs and time required in hand-coding one.

Setting struct member alignment

The C Way

It's done through a command line switch which affects the entire program, and woe results if any modules or libraries didn't get recompiled. To address this, #pragmas are used:
#pragma pack(1)
struct ABC
{
   ...
};
#pragma pack()
But #pragmas are nonportable both in theory and in practice from compiler to compiler.

The D Way

D has a syntax for setting the alignment that is common to all D compilers. The actual alignment done is compatible with the companion C compiler's alignment, for ABI compatibility. To match a particular layout across architectures, use align(1) and manually specify it.

struct ABC
{
   int z;               // z is aligned to the default

 align (1) int x;       // x is byte aligned
 align (4)
 {
   ...                  // declarations in {} are dword aligned
 }
 align (2):             // switch to word alignment from here on

   int y;               // y is word aligned
}

Anonymous Structs and Unions

Sometimes, it's nice to control the layout of a struct with nested structs and unions.

The C Way

C doesn't allow anonymous structs or unions, which means that dummy tag names and dummy members are necessary:
struct Foo
{
   int i;
   union Bar
   {
      struct Abc { int x; long y; } _abc;
      char *p;
   } _bar;
};

#define x _bar._abc.x
#define y _bar._abc.y
#define p _bar.p

struct Foo f;

f.i;
f.x;
f.y;
f.p;
Not only is it clumsy, but using macros means a symbolic debugger won't understand what is being done, and the macros have global scope instead of struct scope.

The D Way

Anonymous structs and unions are used to control the layout in a more natural manner:
struct Foo
{
   int i;
   union
   {
      struct { int x; long y; }
      char* p;
   }
}

Foo f;

f.i;
f.x;
f.y;
f.p;

Declaring struct types and variables

The C Way

Is to do it in one statement ending with a semicolon:

struct Foo { int x; int y; } foo;

Or to separate the two:

struct Foo { int x; int y; };   // note terminating ;
struct Foo foo;

The D Way

Struct definitions and declarations can't be done in the same statement:

struct Foo { int x; int y; }    // note there is no terminating ;
Foo foo;

which means that the terminating ; can be dispensed with, eliminating the confusing difference between struct {} and function block {} in how semicolons are used.

Getting the offset of a struct member

The C Way

Naturally, another macro is used:
#include <stddef>
struct Foo { int x; int y; };

off = offsetof(Foo, y);

The D Way

An offset is just another property:
struct Foo { int x; int y; }

off = Foo.y.offsetof;

Union Initializations

The C Way

Unions are initialized using the "first member" rule:
union U { int a; long b; };
union U x = { 5 };                // initialize member 'a' to 5
Adding union members or rearranging them can have disastrous consequences for any initializers.

The D Way

In D, which member is being initialized is mentioned explicitly:
union U { int a; long b; }
U x = { a:5 };
avoiding the confusion and maintenance problems.

Struct Initializations

The C Way

Members are initialized by their position within the { }s:
struct S { int a; int b; };
struct S x = { 5, 3 };
This isn't much of a problem with small structs, but when there are numerous members, it becomes tedious to get the initializers carefully lined up with the field declarations. Then, if members are added or rearranged, all the initializations have to be found and modified appropriately. This is a minefield for bugs.

The D Way

Member initialization can be done explicitly:
struct S { int a; int b; }
S x = { b:3, a:5 };
The meaning is clear, and there no longer is a positional dependence.

Array Initializations

The C Way

C initializes array by positional dependence:
int a[3] = { 3,2,2 };
Nested arrays may or may not have the { }:
int b[3][2] = { 2,3, {6,5}, 3,4 };

The D Way

D does it by positional dependence too, but an index can be used as well. The following all produce the same result:
int[3] a = [ 3, 2, 0 ];
int[3] a = [ 3, 2 ];            // unsupplied initializers are 0, just like in C
int[3] a = [ 2:0, 0:3, 1:2 ];
int[3] a = [ 2:0, 0:3, 2 ];     // if not supplied, the index is the
                // previous one plus one.
This can be handy if the array will be indexed by an enum, and the order of enums may be changed or added to:
enum color { black, red, green }
int[3] c = [ black:3, green:2, red:5 ];
Nested array initializations must be explicit:
int[2][3] b = [ [2,3], [6,5], [3,4] ];

int[2][3] b = [[2,6,3],[3,5,4]];            // error

Escaped String Literals

The C Way

C has problems with the DOS file system because a \ is an escape in a string. To specifiy file c:\root\file.c:
char file[] = "c:\\root\\file.c";
This gets even more unpleasant with regular expressions. Consider the escape sequence to match a quoted string:
/"[^\\]*(\\.[^\\]*)*"/

In C, this horror is expressed as:

char quoteString[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\"";

The D Way

Within strings, it is WYSIWYG (what you see is what you get). Escapes are in separate strings. So:
char[] file = `c:\root\file.c`;
char[] quoteString = \"  r"[^\\]*(\\.[^\\]*)*"  \";
The famous hello world string becomes:
char[] hello = "hello world" \n;

Ascii vs Wide Characters

Modern programming requires that wchar strings be supported in an easy way, for internationalization of the programs.

The C Way

C uses the wchar_t and the L prefix on strings:
#include <wchar.h>
char foo_ascii[] = "hello";
wchar_t foo_wchar[] = L"hello";
Things get worse if code is written to be both ascii and wchar compatible. A macro is used to switch strings from ascii to wchar:
#include <tchar.h>
tchar string[] = TEXT("hello");

The D Way

The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call:
char[] foo_ascii = "hello";        // string is taken to be ascii
wchar[] foo_wchar = "hello";       // string is taken to be wchar

Arrays that parallel an enum

The C Way

Consider:
enum COLORS { red, blue, green, max };
char *cstring[max] = {"red", "blue", "green" };
This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added.

The D Way

enum COLORS { red, blue, green }

char[][COLORS.max + 1] cstring =
[
    COLORS.red   : "red",
    COLORS.blue  : "blue",
    COLORS.green : "green",
];
Not perfect, but better.

Creating a new type with typedef

The C Way

Typedefs in C are weak, that is, they really do not introduce a new type. The compiler doesn't distinguish between a typedef and its underlying type.
typedef void *Handle;
void foo(void *);
void bar(Handle);

Handle h;
foo(h);			// coding bug not caught
bar(h);			// ok
The C solution is to create a dummy struct whose sole purpose is to get type checking and overloading on the new type.
struct Handle__ { void *value; }
typedef struct Handle__ *Handle;
void foo(void *);
void bar(Handle);

Handle h;
foo(h);			// syntax error
bar(h);			// ok
Having a default value for the type involves defining a macro, a naming convention, and then pedantically following that convention:
#define HANDLE_INIT ((Handle)-1)

Handle h = HANDLE_INIT;
h = func();
if (h != HANDLE_INIT)
    ...
For the struct solution, things get even more complex:
struct Handle__ HANDLE_INIT;

void init_handle()	// call this function upon startup
{
    HANDLE_INIT.value = (void *)-1;
}

Handle h = HANDLE_INIT;
h = func();
if (memcmp(&h,&HANDLE_INIT,sizeof(Handle)) != 0)
    ...
There are 4 names to remember: Handle, HANDLE_INIT, struct Handle__, value.

The D Way

No need for idiomatic constructions like the above. Just write:
typedef void* Handle;
void foo(void*);
void bar(Handle);

Handle h;
foo(h);
bar(h);
To handle a default value, add an initializer to the typedef, and refer to it with the .init property:
typedef void* Handle = cast(void*)(-1);
Handle h;
h = func();
if (h != Handle.init)
    ...
There's only one name to remember: Handle.

Comparing structs

The C Way

While C defines struct assignment in a simple, convenient manner:
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;
...
if (memcmp(&x, &y, sizeof(struct A)) == 0)
    ...
Note the obtuseness of this, coupled with the lack of any kind of help from the language with type checking.

There's a nasty bug lurking in the memcmp(). 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.

The D Way

D does it the obvious, straightforward way:
A x, y;
...
if (x == y)
    ...

Comparing strings

The C Way

The library function strcmp() is used:
char string[] = "hello";

if (strcmp(string, "betty") == 0)	// do strings match?
    ...
C uses 0 terminated strings, so the C way has an inherent inefficiency in constantly scanning for the terminating 0.

The D Way

Why not use the == operator?
char[] string = "hello";

if (string == "betty")
    ...
D strings have the length stored separately from the string. Thus, the implementation of string compares can be much faster than in C (the difference being equivalent to the difference in speed between the C memcmp() and strcmp()).

D supports comparison operators on strings, too:

char[] string = "hello";

if (string < "betty")
    ...
which is useful for sorting/searching.

Sorting arrays

The C Way

Although many C programmers tend to reimplmement bubble sorts over and over, the right way to sort in C is to use qsort():
int compare(const void *p1, const void *p2)
{
    type *t1 = (type *)p1;
    type *t2 = (type *)p2;

    return *t1 - *t2;
}

type array[10];
...
qsort(array, sizeof(array)/sizeof(array[0]),
    sizeof(array[0]), compare);
A compare() must be written for each type, and much careful typo-prone code needs to be written to make it work.

The D Way

Sorting couldn't be easier:
type[] array;
...
array.sort;      // sort array in-place

Volatile memory access

The C Way

To access volatile memory, such as shared memory or memory mapped I/O, a pointer to volatile is created:
volatile int *p = address;

i = *p;

The D Way

D has volatile as a statement type, not as a type modifier:
int* p = address;

volatile { i = *p; }

String literals

The C Way

String literals in C cannot span multiple lines, so to have a block of text it is necessary to use \ line splicing:
"This text spans\n\
multiple\n\
lines\n"
If there is a lot of text, this can wind up being tedious.

The D Way

String literals can span multiple lines, as in:
"This text spans
multiple
lines
"
So blocks of text can just be cut and pasted into the D source.

Data Structure Traversal

The C Way

Consider a function to traverse a recursive data structure. In this example, there's a simple symbol table of strings. The data structure is an array of binary trees. The code needs to do an exhaustive search of it to find a particular string in it, and determine if it is a unique instance.

To make this work, a helper function membersearchx is needed to recursively walk the trees. The helper function needs to read and write some context outside of the trees, so a custom struct Paramblock is created and a pointer to it is used to maximize efficiency.

struct Symbol
{
   char *id;
   struct Symbol *left;
   struct Symbol *right;
};

struct Paramblock
{
   char *id;
   struct Symbol *sm;
};

static void membersearchx(struct Paramblock *p, struct Symbol *s)
{
   while (s)
   {
      if (strcmp(p->id,s->id) == 0)
      {
         if (p->sm)
            error("ambiguous member %s\n",p->id);
         p->sm = s;
      }

      if (s->left)
         membersearchx(p,s->left);
      s = s->right;
   }
}

struct Symbol *symbol_membersearch(Symbol *table[], int tablemax, char *id)
{
   struct Paramblock pb;
   int i;

   pb.id = id;
   pb.sm = NULL;
   for (i = 0; i < tablemax; i++)
   {
      membersearchx(pb, table[i]);
   }
   return pb.sm;
}

The D Way

This is the same algorithm in D, and it shrinks dramatically. Since nested functions have access to the lexically enclosing function's variables, there's no need for a Paramblock or to deal with its bookkeeping details. The nested helper function is contained wholly within the function that needs it, improving locality and maintainability.

The performance of the two versions is indistinguishable.

class Symbol
{   char[] id;
    Symbol left;
    Symbol right;
}

Symbol symbol_membersearch(Symbol[] table, char[] id)
{   Symbol sm;

    void membersearchx(Symbol s)
    {
    while (s)
    {
        if (id == s.id)
        {
        if (sm)
            error("ambiguous member %s\n", id);
        sm = s;
        }

        if (s.left)
        membersearchx(s.left);
        s = s.right;
    }
    }

    for (int i = 0; i < table.length; i++)
    {
    membersearchx(table[i]);
    }
    return sm;
}

Unsigned Right Shift

The C Way

The right shift operators >> and >>= are signed shifts if the left operand is a signed integral type, and are unsigned right shifts if the left operand is an unsigned integral type. To produce an unsigned right shift on an int, a cast is necessary:
int i, j;
...
j = (unsigned)i >> 3;
If i is an int, this works fine. But if i is of a type created with typedef,
myint i, j;
...
j = (unsigned)i >> 3;
and myint happens to be a long int, then the cast to unsigned will silently throw away the most significant bits, corrupting the answer.

The D Way

D has the right shift operators >> and >>= which behave as they do in C. But D also has explicitly unsigned right shift operators >>> and >>>= which will do an unsigned right shift regardless of the sign of the left operand. Hence,
myint i, j;
...
j = i >>> 3;
avoids the unsafe cast and will work as expected with any integral type.

Dynamic Closures

The C Way

Consider a reusable container type. In order to be reusable, it must support a way to apply arbitrary code to each element of the container. This is done by creating an apply function that accepts a function pointer to which is passed each element of the container contents.

A generic context pointer is also needed, represented here by void *p. The example here is of a trivial container class that holds an array of ints, and a user of that container that computes the maximum of those ints.

void apply(void *p, int *array, int dim, void (*fp)(void *, int))
{
    for (int i = 0; i < dim; i++)
    fp(p, array[i]);
}

struct Collection
{
    int array[10];
};

void comp_max(void *p, int i)
{
    int *pmax = (int *)p;

    if (i > *pmax)
    *pmax = i;
}

void func(struct Collection *c)
{
    int max = INT_MIN;

    apply(&max, c->array, sizeof(c->array)/sizeof(c->array[0]), comp_max);
}

While this works, it isn't very flexible.

The D Way

The D version makes use of delegates to transmit context information for the apply function, and nested functions both to capture context information and to improve locality.
class Collection
{
    int[10] array;

    void apply(void delegate(int) fp)
    {
    for (int i = 0; i < array.length; i++)
        fp(array[i]);
    }
}

void func(Collection c)
{
    int max = int.min;

    void comp_max(int i)
    {
    if (i > max)
        max = i;
    }

    c.apply(comp_max);
}
Pointers are eliminated, as well as casting and generic pointers. The D version is fully type safe. An alternate method in D makes use of function literals:
void func(Collection c)
{
    int max = int.min;

    c.apply(delegate(int i) { if (i > max) max = i; } );
}
eliminating the need to create irrelevant function names.

Variadic Function Parameters

The task is to write a function that takes a varying number of arguments, such as a function that sums its arguments.

The C Way

#include <stdio.h>
#include <stdarg.h>

int sum(int dim, ...)
{   int i;
    int s = 0;
    va_list ap;

    va_start(ap, dim);
    for (i = 0; i < dim; i++)
    s += va_arg(ap, int);
    va_end(ap);
    return s;
}

int main()
{
    int i;

    i = sum(3, 8,7,6);
    printf("sum = %d\n", i);

    return 0;
}
There are two problems with this. The first is that the sum function needs to know how many arguments were supplied. It has to be explicitly written, and it can get out of sync with respect to the actual number of arguments written. The second is that there's no way to check that the types of the arguments provided really were ints, and not doubles, strings, structs, etc.

The D Way

The ... following an array parameter declaration means that the trailing arguments are collected together to form an array. The arguments are type checked against the array type, and the number of arguments becomes a property of the array:
import std.stdio;

int sum(int[] values ...)
{
    int s = 0;

    foreach (int x; values)
    s += x;
    return s;
}

int main()
{
    int i;

    i = sum(8,7,6);
    writefln("sum = %d", i);

    return 0;
}


Programming in D for C++ Programmers

Last update Sun Dec 30 20:34:42 2012

Programming in D for C++ Programmers

C++ Every experienced C++ programmer accumulates a series of idioms and techniques which become second nature. Sometimes, when learning a new language, those idioms can be so comfortable it's hard to see how to do the equivalent in the new language. So here's a collection of common C++ techniques, and how to do the corresponding task in D.

See also: Programming in D for C Programmers

  • Defining Constructors
  • Base class initialization
  • Comparing structs
  • Creating a new typedef'd type
  • Friends
  • Operator overloading
  • Namespace using declarations
  • RAII (Resource Acquisition Is Initialization)
  • Properties
  • Recursive Templates
  • Meta Templates
  • Type Traits

Defining constructors

The C++ Way

Constructors have the same name as the class:
class Foo
{
    Foo(int x);
};

The D Way

Constructors are defined with the this keyword:
class Foo
{
    this(int x) { }
}
which reflects how they are used in D.

Base class initialization

The C++ Way

Base constructors are called using the base initializer syntax.
class A { A() {... } };
class B : A
{
     B(int x)
    : A()		// call base constructor
     {	...
     }
};

The D Way

The base class constructor is called with the super syntax:
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;
    }
}

Comparing structs

The C++ Way

While C++ defines struct assignment in a simple, convenient manner:
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++.

The D Way

D does it the obvious, straightforward way:
A x, y;
...
if (x == y)
    ...

Creating a new typedef'd type

The C++ Way

Typedef's in C++ are weak, that is, they really do not introduce a new type. The compiler doesn't distinguish between a typedef and its underlying type.
#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);			// ok
The 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;

    // default initializer
    Handle() { ptr = HANDLE_INIT; }

    Handle(int i) { ptr = (void *)i; }

    // conversion to underlying type
    operator void*() { return ptr; }
};
void bar(Handle);

Handle h;
bar(h);
h = func();
if (h != HANDLE_INIT)
    ...

The D Way

No need for idiomatic constructions like the above. Just write:
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.

Friends

The C++ Way

Sometimes two classes are tightly related but not by inheritance, but need to access each other's private members. This is done using friend declarations:
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; }

The D Way

In D, friend access is implicit in being a member of the same module. It makes sense that tightly related classes should be in the same module, so implicitly granting friend access to other module members solves the problem neatly:
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.

Operator overloading

The C++ Way

Given a struct that creates a new arithmetic data type, it's convenient to overload the comparison operators so it can be compared against integers:
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.

The D Way

D recognizes that the comparison operators are all fundamentally related to each other. So only one function is 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 using declarations

The C++ Way

A using-declaration in C++ is used to bring a name from a namespace scope into the current scope:
namespace foo
{
    int x;
}
using foo::x;

The D Way

D uses modules instead of namespaces and #include files, and alias declarations take the place of using declarations:
/** 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.

RAII (Resource Acquisition Is Initialization)

The C++ Way

In C++, resources like memory, etc., all need to be handled explicitly. Since destructors automatically get called when leaving a scope, RAII is implemented by putting the resource release code into the destructor:
class File
{   Handle *h;

    ~File()
    {
    h->release();
    }
};

The D Way

The bulk of resource release problems are simply keeping track of and freeing memory. This is handled automatically in D by the garbage collector. The second common resources used are semaphores and locks, handled automatically with D's synchronized declarations and statements.

The few RAII issues left are handled by scope classes. Scope classes get their destructors run when they go out of scope.

scope class File
{   Handle h;

    ~this()
    {
    h.release();
    }
}

void test()
{
    if (...)
    {   scope f = new File();
    ...
    } // f.~this() gets run at closing brace, even if
      // scope was exited via a thrown exception
}

Properties

The C++ Way

It is common practice to define a field, along with object-oriented get and set functions for it:
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.

The D Way

Properties can be get and set using the normal field syntax, yet the get and set will invoke methods instead.
class Abc
{
    // set
    void property(int newproperty) { myprop = newproperty; }

    // get
    int property() { return myprop; }

  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.

Recursive Templates

The C++ Way

An advanced use of templates is to recursively expand them, relying on specialization to end it. A template to compute a factorial would be:
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
}

The D Way

The D version is analogous, though a little simpler, taking advantage of promotion of single template members to the enclosing name space:
template factorial(int n)
{
    enum { factorial = n * .factorial!(n-1) }
}

template factorial(int n : 1)
{
    enum { factorial = 1 }
}

void test()
{
    writefln("%d", factorial!(4));	// prints 24
}

Meta Templates

The problem: create a typedef for a signed integral type that is at least nbits in size.

The C++ Way

This example is simplified and adapted from one written by Dr. Carlo Pescio in Template Metaprogramming: Make parameterized integers portable with this novel technique.

There is no way in C++ to do conditional compilation based on the result of an expression based on template parameters, so all control flow follows from pattern matching of the template argument against various explicit template specializations. Even worse, there is no way to do template specializations based on relationships like "less than or equal to", so the example uses a clever technique where the template is recursively expanded, incrementing the template value argument by one each time, until a specialization matches. If there is no match, the result is an unhelpful recursive compiler stack overflow or internal error, or at best a strange syntax error.

A preprocessor macro is also needed to make up for the lack of template typedefs.

#include <limits.h>

template< int nbits > struct Integer
{
    typedef Integer< nbits + 1 > :: int_type int_type ;
} ;

struct Integer< 8 >
{
    typedef signed char int_type ;
} ;

struct Integer< 16 >
{
    typedef short int_type ;
} ;

struct Integer< 32 >
{
    typedef int int_type ;
} ;

struct Integer< 64 >
{
    typedef long long int_type ;
} ;

// If the required size is not supported, the metaprogram
// will increase the counter until an internal error is
// signaled, or INT_MAX is reached. The INT_MAX
// specialization does not define a int_type, so a
// compiling error is always generated
struct Integer< INT_MAX >
{
} ;

// A bit of syntactic sugar
#define Integer( nbits ) Integer< nbits > :: int_type

#include <stdio.h>

int main()
{
    Integer( 8 ) i ;
    Integer( 16 ) j ;
    Integer( 29 ) k ;
    Integer( 64 ) l ;
    printf("%d %d %d %d\n",
    sizeof(i), sizeof(j), sizeof(k), sizeof(l));
    return 0 ;
}

The C++ Boost Way

This version uses the C++ Boost library. It was provided by David Abrahams.
#include <boost/mpl/if.hpp>
#include <boost/mpl/assert.hpp>

template <int nbits> struct Integer
    : mpl::if_c<(nbits <= 8), signed char
    , mpl::if_c<(nbits <= 16), short
    , mpl::if_c<(nbits <= 32), long
    , long long>::type >::type >
{
    BOOST_MPL_ASSERT_RELATION(nbits, <=, 64);
}

#include <stdio.h>

int main()
{
    Integer< 8 > i ;
    Integer< 16 > j ;
    Integer< 29 > k ;
    Integer< 64 > l ;
    printf("%d %d %d %d\n",
    sizeof(i), sizeof(j), sizeof(k), sizeof(l));
    return 0 ;
}

The D Way

The D version could also be written with recursive templates, but there's a better way. Unlike the C++ example, this one is fairly easy to figure out what is going on. It compiles quickly, and gives a sensible compile time message if it fails.
import std.stdio;

template Integer(int nbits)
{
    static if (nbits <= 8)
    alias byte Integer;
    else static if (nbits <= 16)
    alias short Integer;
    else static if (nbits <= 32)
    alias int Integer;
    else static if (nbits <= 64)
    alias long Integer;
    else
    static assert(0);
}

int main()
{
    Integer!(8) i ;
    Integer!(16) j ;
    Integer!(29) k ;
    Integer!(64) l ;
    writefln("%d %d %d %d",
    i.sizeof, j.sizeof, k.sizeof, l.sizeof);
    return 0;
}

Type Traits

Type traits are another term for being able to find out properties of a type at compile time.

The C++ Way

The following template comes from C++ Templates: The Complete Guide, David Vandevoorde, Nicolai M. Josuttis pg. 353 which determines if the template's argument type is a function:
template<typename T> class IsFunctionT
{
    private:
    typedef char One;
    typedef struct { char a[2]; } Two;
    template<typename U> static One test(...);
    template<typename U> static Two test(U (*)[1]);
    public:
    enum { Yes = sizeof(IsFunctionT<T>::test<T>(0)) == 1 };
};

void test()
{
    typedef int (fp)(int);

    assert(IsFunctionT<fp>::Yes == 1);
}
This template relies on the SFINAE (Substitution Failure Is Not An Error) principle. Why it works is a fairly advanced template topic.

The D Way

SFINAE (Substitution Failure Is Not An Error) can be done in D without resorting to template argument pattern matching:
template IsFunctionT(T)
{
    static if ( is(T[]) )
    const int IsFunctionT = 0;
    else
    const int IsFunctionT = 1;
}

void test()
{
    typedef int fp(int);

    assert(IsFunctionT!(fp) == 1);
}
The task of discovering if a type is a function doesn't need a template at all, nor does it need the subterfuge of attempting to create the invalid array of functions type. The IsExpression expression can test it directly:
void test()
{
    alias int fp(int);

    assert( is(fp == function) );
}


The C Preprocessor vs D

Last update Sun Dec 30 20:34:42 2012

The C Preprocessor Versus D

Back when C was invented, compiler technology was primitive. Installing a text macro preprocessor onto the front end was a straightforward and easy way to add many powerful features. The increasing size & complexity of programs have illustrated that these features come with many inherent problems. D doesn't have a preprocessor; but D provides a more scalable means to solve the same problems.

  • Header Files
  • #pragma once
  • #pragma pack
  • Macros
  • Conditional Compilation
  • Code Factoring
  • #error and Static Asserts
  • Template Mixins

Header Files

The C Preprocessor Way

C and C++ rely heavily on textual inclusion of header files. This frequently results in the compiler having to recompile tens of thousands of lines of code over and over again for every source file, an obvious source of slow compile times. What header files are normally used for is more appropriately done doing a symbolic, rather than textual, insertion. This is done with the import statement. Symbolic inclusion means the compiler just loads an already compiled symbol table. The needs for macro "wrappers" to prevent multiple #inclusion, funky #pragma once syntax, and incomprehensible fragile syntax for precompiled headers are simply unnecessary and irrelevant to D.

#include <stdio.h>

The D Way

D uses symbolic imports:

import std.c.stdio;

#pragma once

The C Preprocessor Way

C header files frequently need to be protected against being #include'd multiple times. To do it, a header file will contain the line:

#pragma once

or the more portable:

#ifndef __STDIO_INCLUDE
#define __STDIO_INCLUDE
... header file contents
#endif

The D Way

Completely unnecessary since D does a symbolic include of import files; they only get imported once no matter how many times the import declaration appears.

#pragma pack

The C Preprocessor Way

This is used in C to adjust the alignment for structs.

The D Way

For D classes, there is no need to adjust the alignment (in fact, the compiler is free to rearrange the data fields to get the optimum layout, much as the compiler will rearrange local variables on the stack frame). For D structs that get mapped onto externally defined data structures, there is a need, and it is handled with:

struct Foo
{
    align (4):	// use 4 byte alignment
    ...
}

Macros

Preprocessor macros add powerful features and flexibility to C. But they have a downside:

  • Macros have no concept of scope; they are valid from the point of definition to the end of the source. They cut a swath across .h files, nested code, etc. When #include'ing tens of thousands of lines of macro definitions, it becomes problematical to avoid inadvertent macro expansions.
  • Macros are unknown to the debugger. Trying to debug a program with symbolic data is undermined by the debugger only knowing about macro expansions, not the macros themselves.
  • Macros make it impossible to tokenize source code, as an earlier macro change can arbitrarily redo tokens.
  • The purely textual basis of macros leads to arbitrary and inconsistent usage, making code using macros error prone. (Some attempt to resolve this was introduced with templates in C++.)
  • Macros are still used to make up for deficits in the language's expressive capability, such as for "wrappers" around header files.

Here's an enumeration of the common uses for macros, and the corresponding feature in D:

  1. Defining literal constants:

    The C Preprocessor Way

    #define VALUE	5

    The D Way

    const int VALUE = 5;
  2. Creating a list of values or flags:

    The C Preprocessor Way

    int flags:
#define FLAG_X	0x1
#define FLAG_Y	0x2
#define FLAG_Z	0x4
...
flags |= FLAG_X;

    The D Way

    enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
FLAGS flags;
...
flags |= FLAGS.X;
  3. Distinguishing between ascii chars and wchar chars:

    The C Preprocessor Way

    #if UNICODE
    #define dchar	wchar_t
    #define TEXT(s)	L##s
#else
    #define dchar	char
    #define TEXT(s)	s
#endif

...
dchar h[] = TEXT("hello");

    The D Way

    dchar[] h = "hello";
    D's optimizer will inline the function, and will do the conversion of the string constant at compile time.

  4. Supporting legacy compilers:

    The C Preprocessor Way

    #if PROTOTYPES
#define P(p)	p
#else
#define P(p)	()
#endif
int func P((int x, int y));

    The D Way

    By making the D compiler open source, it will largely avoid the problem of syntactical backwards compatibility.
  5. Type aliasing:

    The C Preprocessor Way

    #define INT 	int

    The D Way

    alias int INT;
  6. Using one header file for both declaration and definition:

    The C Preprocessor Way

    #define EXTERN extern
#include "declarations.h"
#undef EXTERN
#define EXTERN
#include "declarations.h"
    In declarations.h:
    EXTERN int foo;

    The D Way

    The declaration and the definition are the same, so there is no need to muck with the storage class to generate both a declaration and a definition from the same source.
  7. Lightweight inline functions:

    The C Preprocessor Way

    #define X(i)	((i) = (i) / 3)

    The D Way

    int X(ref int i) { return i = i / 3; }
    The compiler optimizer will inline it; no efficiency is lost.
  8. Assert function file and line number information:

    The C Preprocessor Way

    #define assert(e)	((e) || _assert(__LINE__, __FILE__))

    The D Way

    assert() is a built-in expression primitive. Giving the compiler such knowledge of assert() also enables the optimizer to know about things like the _assert() function never returns.
  9. Setting function calling conventions:

    The C Preprocessor Way

    #ifndef _CRTAPI1
#define _CRTAPI1 __cdecl
#endif
#ifndef _CRTAPI2
#define _CRTAPI2 __cdecl
#endif

int _CRTAPI2 func();

    The D Way

    Calling conventions can be specified in blocks, so there's no need to change it for every function:
    extern (Windows)
{
    int onefunc();
    int anotherfunc();
}
  10. Hiding __near or __far pointer weirdness:

    The C Preprocessor Way

    #define LPSTR	char FAR *

    The D Way

    D doesn't support 16 bit code, mixed pointer sizes, and different kinds of pointers, and so the problem is just irrelevant.
  11. Simple generic programming:

    The C Preprocessor Way

    Selecting which function to use based on text substitution:
    #ifdef UNICODE
int getValueW(wchar_t *p);
#define getValue getValueW
#else
int getValueA(char *p);
#define getValue getValueA
#endif

    The D Way

    D enables declarations of symbols that are aliases of other symbols:
    version (UNICODE)
{
    int getValueW(wchar[] p);
    alias getValueW getValue;
}
else
{
    int getValueA(char[] p);
    alias getValueA getValue;
}

Conditional Compilation

The C Preprocessor Way

Conditional compilation is a powerful feature of the C preprocessor, but it has its downside:

  • The preprocessor has no concept of scope. #if/#endif can be interleaved with code in a completely unstructured and disorganized fashion, making things difficult to follow.
  • Conditional compilation triggers off of macros - macros that can conflict with identifiers used in the program.
  • #if expressions are evaluated in subtly different ways than C expressions are.
  • The preprocessor language is fundamentally different in concept than C, for example, whitespace and line terminators mean things to the preprocessor that they do not in C.

The D Way

D supports conditional compilation:

  1. Separating version specific functionality into separate modules.
  2. The debug statement for enabling/disabling debug harnesses, extra printing, etc.
  3. The version statement for dealing with multiple versions of the program generated from a single set of sources.
  4. The if (0) statement.
  5. The /+ +/ nesting comment can be used to comment out blocks of code.

Code Factoring

The C Preprocessor Way

It's common in a function to have a repetitive sequence of code to be executed in multiple places. Performance considerations preclude factoring it out into a separate function, so it is implemented as a macro. For example, consider this fragment from a byte code interpreter:

unsigned char *ip;	// byte code instruction pointer
int *stack;
int spi;		// stack pointer
...
#define pop()		(stack[--spi])
#define push(i)		(stack[spi++] = (i))
while (1)
{
    switch (*ip++)
    {
    case ADD:
        op1 = pop();
        op2 = pop();
        result = op1 + op2;
        push(result);
        break;

    case SUB:
    ...
    }
}

This suffers from numerous problems:

  1. The macros must evaluate to expressions and cannot declare any variables. Consider the difficulty of extending them to check for stack overflow/underflow.
  2. The macros exist outside of the semantic symbol table, so remain in scope even outside of the function they are declared in.
  3. Parameters to macros are passed textually, not by value, meaning that the macro implementation needs to be careful to not use the parameter more than once, and must protect it with ().
  4. Macros are invisible to the debugger, which sees only the expanded expressions.

The D Way

D neatly addresses this with nested functions:

ubyte* ip;		// byte code instruction pointer
int[] stack;		// operand stack
int spi;		// stack pointer
...

int pop()        { return stack[--spi]; }
void push(int i) { stack[spi++] = i; }

while (1)
{
    switch (*ip++)
    {
    case ADD:
        op1 = pop();
        op2 = pop();
        push(op1 + op2);
        break;

    case SUB:
    ...
    }
}

The problems addressed are:

  1. The nested functions have available the full expressive power of D functions. The array accesses already are bounds checked (adjustable by compile time switch).
  2. Nested function names are scoped just like any other name.
  3. Parameters are passed by value, so need to worry about side effects in the parameter expressions.
  4. Nested functions are visible to the debugger.

Additionally, nested functions can be inlined by the implementation resulting in the same high performance that the C macro version exhibits.

#error and Static Asserts

Static asserts are user defined checks made at compile time; if the check fails the compile issues an error and fails.

The C Preprocessor Way

The first way is to use the #error preprocessing directive:

#if FOO || BAR
    ... code to compile ...
#else
#error "there must be either FOO or BAR"
#endif

This has the limitations inherent in preprocessor expressions (i.e. integer constant expressions only, no casts, no sizeof, no symbolic constants, etc.).

These problems can be circumvented to some extent by defining a static_assert macro (thanks to M. Wilson):

#define static_assert(_x) do { typedef int ai[(_x) ? 1 : 0]; } while(0)

and using it like:

void foo(T t)
{
    static_assert(sizeof(T) < 4);
    ...
}

This works by causing a compile time semantic error if the condition evaluates to false. The limitations of this technique are a sometimes very confusing error message from the compiler, along with an inability to use a static_assert outside of a function body.

The D Way

D has the static assert, which can be used anywhere a declaration or a statement can be used. For example:

version (FOO)
{
    class Bar
    {
    const int x = 5;
    static assert(Bar.x == 5 || Bar.x == 6);

    void foo(T t)
    {
        static assert(T.sizeof < 4);
        ...
    }
    }
}
else version (BAR)
{
    ...
}
else
{
    static assert(0);	// unsupported version
}

Template Mixins

D template mixins superficially look just like using C's preprocessor to insert blocks of code and parse them in the scope of where they are instantiated. But the advantages of mixins over macros are:

  1. Mixins substitute in parsed declaration trees that pass muster with the language syntax, macros substitute in arbitrary preprocessor tokens that have no organization.
  2. Mixins are in the same language. Macros are a separate and distinct language layered on top of C++, with its own expression rules, its own types, its distinct symbol table, its own scoping rules, etc.
  3. Mixins are selected based on partial specialization rules, macros have no overloading.
  4. Mixins create a scope, macros do not.
  5. Mixins are compatible with syntax parsing tools, macros are not.
  6. Mixin semantic information and symbol tables are passed through to the debugger, macros are lost in translation.
  7. Mixins have override conflict resolution rules, macros just collide.
  8. Mixins automatically create unique identifiers as required using a standard algorithm, macros have to do it manually with kludgy token pasting.
  9. Mixin value arguments with side effects are evaluated once, macro value arguments get evaluated each time they are used in the expansion (leading to weird bugs).
  10. Mixin argument replacements don't need to be 'protected' with parentheses to avoid operator precedence regrouping.
  11. Mixins can be typed as normal D code of arbitrary length, multiline macros have to be backslash line-spliced, can't use // to end of line comments, etc.
  12. Mixins can define other mixins. Macros cannot create other macros.


Template Comparison

Last update Sun Dec 30 20:34:43 2012

Template Comparison

C++ pioneered templates and template metaprogramming, and continues to improve on it with C++0x. The D programming language is the first to comprehensively reengineer templates based on the C++ experience. Since C++0x is not a ratified standard yet, proposed changes to C++ are subject to change.

Template Comparison Table
Feature | D | C++98 | C++0x
Argument list delineation | Uses !( ), as in Foo!(int) | Uses < > as in Foo<int> | No change
Class Templates Yes:
class Foo(T)
{
  T x;
}
Yes:
template<class T>
  class Foo
{
  T x;
};
No change
Function Templates Yes:
T foo(T)(T i)
{
  ...
}
Yes:
template<class T>
  T foo(T i)
{
  ...
}
No change
Member Templates | Yes | Yes | No change
Constructor Templates | No | Yes | No change
Parameterize any Declaration Yes, classes, functions, typedefs, variables, enums, etc. can be parameterized, such as this variable:
template Foo(T)
{
  static T* p;
}
No, only classes and functions No change
Template Typedefs: Create an alias that binds to some but not all of the template parameters Yes:
class Foo(T, U) { }
template MyFoo(T)
{
  alias Foo!(T, int) MyFoo;
}
MyFoo!(uint) f;
No Yes:
template<class T, class U> class Foo { };
template<class T> using MyFoo = Foo<T, int>;
MyFoo<unsigned> f;
Sequence Constructors No No Yes:
Foo<double> f = { 1.2, 3, 6.8 };
Concepts | No, but much the same effect can be achieved with StaticIfCondition and static asserts | No | Yes: Concepts for C++0x N1849
Recursive Templates Yes:
template factorial(int n)
{
  const factorial =
     n * factorial!(n-1);
}
template factorial(int n : 1)
{
  const factorial = 1;
}
Yes:
template<int n> class factorial
{
  public:
    enum
    {
      result =
         n * factorial<n-1>::result
    };
};
template<> class factorial<1>
{
  public:
    enum { result = 1 };
};
No change
Conditional Compilation based on Template Arguments Yes:
template factorial(int n)
{
  static if (n == 1)
    const factorial = 1;
  else
    const factorial =
       n * factorial!(n-1);
}
No:
template<int n> class factorial
{
  public:
    enum
    {
#if (n == 1) // error
      result = 1;
#else
      result =
         n * factorial<n-1>::result
#endif
    };
};
No change
Template Declarations (with no definition) No Yes:
template<class T>
  class Foo;
No change
Grouping templates with the same parameters together Yes:
template Foo(T, U)
{
  class Bar { ... }
  T foo(T t, U u) { ... }
}
Foo!(int,long).Bar b;
return Foo!(char,int).foo('c',3);
No, each must be separate:
template<class T, class U>
  class Foo_Bar { ... };
template<class T, class U>
  T Foo_foo(T t, U u) { ... };
Foo_Bar<int,long> b;
return Foo_foo<char,int>('c',3);
No change
Compile time execution of functions Yes:
int factorial(int i)
{ if (i == 0)
    return 1;
  else
    return i * factorial(i - 1);
}
static f = factorial(6);
No Named constant expressions with parameters: Generalized Constant Expressions N1972
Parameters | D | C++98 | C++0x
Type Parameters Yes:
class Foo(T)
{
  T x;
}
Foo!(int) f;
Yes:
template<class T>
  class Foo
{
  T x;
};
Foo<int> f;
No change
Integral Parameters Yes:
void foo(int i)()
{
  int v = i;
}
Yes:
template<int i>
    void foo()
{
  int v = i;
}
No change
Pointer Parameters | Yes, a pointer to object or function | Yes, a pointer to object or function | No change
Reference Parameters No, D does not have a general reference type Yes:
template<double& D>
    void foo()
{
  double y = D;
}
No change
Pointer to Member Parameters | No, D does not have pointers to members, it has delegates, which can be used as parameters | Yes | No change
Template Template Parameters Yes:
class Foo(T, alias C)
{
  C!(T) x;
}
Yes:
template<class T,
         template<class U> class C>
    class Foo
{
  C<T> x;
};
No change
Alias Parameters Yes, any symbol can be passed to a template as an alias:
void bar(int);
void bar(double);
void foo(T, alias S)(T t)
{
  S(t);
}
// calls bar(double)
foo!(double, bar)(1);
No No change
Floating Point Parameters Yes:
class Foo(double D)
{
  double x = D;
}
...
Foo!(1.6) F;
No No change
String Parameters Yes:
void foo(char[] format)(int i)
{
  writefln(format, i);
}
...
foo!("i = %s")(3);
No No change
Local Class Parameters | Yes | No | Issue N1945
Local Variable Parameters | Yes | No | No change
Parameter Default Values Yes:
class Foo(T = int)
{
  T x;
}
Yes:
template<class T = int>
  class Foo
{
  T x;
};
No change
Variadic Parameters Yes, Variadic Templates:
void print(A...)(A a)
{
    foreach(t; a)
    writefln(t);
}
No Variadic Templates N2080
Specializations | D | C++98 | C++0x
Explicit Specialization Yes:
class Foo(T : int)
{
  T x;
}
Yes:
template<>
  class Foo<int>
{
  int x;
};
No change
Partial Specialization Yes:
class Foo(T : T*, U)
{
  T x;
}
Yes:
template<class T, class U>
  class Foo<T*, U>
{
  T x;
};
No change
Partial specialization derived from multiple parameters Yes:
class Foo(T : Bar!(T, U), U)
{
  ...
}
Yes:
template<class T, class U>
    class Foo< Bar<T,U> >
{
  ...
};
No change
Can specializations exist without a primary template? | Yes | No | No change
Other | D | C++98 | C++0x
Exported Templates | Yes, it falls out as a natural consequence of modules | Yes, though only in compilers based on EDG's front end | No change
SFINAE (Substitution Failure Is Not An Error) | Yes | Yes | No change
Parse Template Definition Bodies before Instantiation | Yes | Not required by Standard, but some implementations do | No change
Overloading Function Templates with Functions No, but the equivalent can be done with explicitly specialized templates:
void foo(T)(T t) { }
void foo(T:int)(int t) { }
Yes:
template<class T>
  void foo(T i) { }
void foo(int t) { }
No change
Implicit Function Template Instantiation | Yes | Yes | No change
Templates can be evaluated in scope of instantiation rather than definition | Yes, Mixins | No, but can be faked using macros | No change
Parsing Idiosyncracies | D | C++98 | C++0x
Context-Free Grammar Yes:
class Foo!(int i)
{
   ...
}
Foo!(3 > 4) f;
No:
template<int i> class Foo
{
   ...
};
Foo<3 > 4> f; // error
No change
Distinguish template arguments from other operators Yes:
class Foo!(T)
{
   ...
}
class Bar!(int i)
{
   ...
}
Foo!(Bar!(1)) x1;
No:
template<class T> class Foo
{
   ...
};
template<int i> class Bar
{
   ...
};
Foo<Bar<1>> x1; // error
Foo<Bar<1> > x2;
Partially fixed by Right Angle Brackets N1757
Redeclaration of Template Parameter Yes:
class Foo(T)
{
  int T;
  void foo()
  {
    int T;
  }
}
No:
template<class T>
  class Foo
{
  int T; // error
  void foo()
  {
    int T; // error
  }
};
No change
Dependent Base Class Lookup Yes:
class Foo(T)
{
  typedef int A;
}
class Bar(T) : Foo(T)
{
  A x;
}
No:
template<class T>
  class Foo
{
  public:
    typedef int A;
};
template<class T>
  class Bar : Foo<T>
{
  public:
    A x; // error
};
No change
Forward Referencing Yes:
int g(void *);

class Foo(T)
{
  int foo()
  {
    return g(1);
  }
}

int g(int i);
No:
int g(void *);

template<class T>
  class Foo
{
  int foo()
  {
    return g(1); // error
  }
};

int g(int i);
No change
Member templates parseable without hints Yes:
class Foo
{
    Foo bar!(int I)();
}
void abd(T)(T f)
{
  T f1 = f.bar!(3)();
}
No:
class Foo
{
  public:
    template<int> Foo *bar();
};
template<class T> void abc(T *f)
{
  T *f1 = f->bar<3>(); // error
  T *f2 = f->template bar<3>();
}
No change
Dependent type members parseable without hints Yes:
class Foo(T)
{
  T.A* a1;
}
No:
template class Foo
{
  public:
    T::A *a1; // error
    typename T::A *a2;
};
No change


D Strings vs C++ Strings

Last update Sun Dec 30 20:34:42 2012

D Strings vs C++ Strings

Why have strings built-in to the core language of D rather than entirely in a library as in C++ Strings? What's the point? Where's the improvement?

Concatenation Operator

C++ Strings are stuck with overloading existing operators. The obvious choice for concatenation is += and +. But someone just looking at the code will see + and think "addition". He'll have to look up the types (and types are frequently buried behind multiple typedef's) to see that it's a string type, and it's not adding strings but concatenating them.

Additionally, if one has an array of floats, is '+' overloaded to be the same as a vector addition, or an array concatenation?

In D, these problems are avoided by introducing a new binary operator ~ as the concatenation operator. It works with arrays (of which strings are a subset). ~= is the corresponding append operator. ~ on arrays of floats would concatenate them, + would imply a vector add. Adding a new operator makes it possible for orthogonality and consistency in the treatment of arrays. (In D, strings are simply arrays of characters, not a special type.)

Interoperability With C String Syntax

Overloading of operators only really works if one of the operands is overloadable. So the C++ string class cannot consistently handle arbitrary expressions containing strings. Consider:

const char abc[5] = "world";
string str = "hello" + abc;

That isn't going to work. But it does work when the core language knows about strings:

const char[5] abc = "world";
char[] str = "hello" ~ abc;

Consistency With C String Syntax

There are three ways to find the length of a string in C++:

const char abc[] = "world";	:	sizeof(abc)/sizeof(abc[0])-1
                :	strlen(abc)
string str;			:	str.length()

That kind of inconsistency makes it hard to write generic templates. Consider D:

char[5] abc = "world";	:	abc.length
char[] str		:	str.length

Checking For Empty Strings

C++ strings use a function to determine if a string is empty:

string str;
if (str.empty())
    // string is empty

In D, an empty string has zero length:

char[] str;
if (!str.length)
    // string is empty

Resizing Existing String

C++ handles this with the resize() member function:

string str;
str.resize(newsize);

D takes advantage of knowing that str is an array, and so resizing it is just changing the length property:

char[] str;
str.length = newsize;

Slicing a String

C++ slices an existing string using a special constructor:

string s1 = "hello world";
string s2(s1, 6, 5);		// s2 is "world"

D has the array slice syntax, not possible with C++:

char[] s1 = "hello world";
char[] s2 = s1[6 .. 11];	// s2 is "world"

Slicing, of course, works with any array in D, not just strings.

Copying a String

C++ copies strings with the replace function:

string s1 = "hello world";
string s2 = "goodbye      ";
s2.replace(8, 5, s1, 6, 5);	// s2 is "goodbye world"

D uses the slice syntax as an lvalue:

char[] s1 = "hello world";
char[] s2 = "goodbye      ".dup;
s2[8..13] = s1[6..11];		// s2 is "goodbye world"

The .dup is needed because string literals are read-only in D, the .dup will create a copy that is writable.

Conversions to C Strings

This is needed for compatibility with C API's. In C++, this uses the c_str() member function:

void foo(const char *);
string s1;
foo(s1.c_str());

In D, strings can be converted to char* using the .ptr property:

void foo(char*);
char[] s1;
foo(s1.ptr);

although for this to work where foo expects a 0 terminated string, s1 must have a terminating 0. Alternatively, the function std.string.toStringz will ensure it:

void foo(char*);
char[] s1;
foo(std.string.toStringz(s1));

Array Bounds Checking

In C++, string array bounds checking for [] is not done. In D, array bounds checking is on by default and it can be turned off with a compiler switch after the program is debugged.

String Switch Statements

Are not possible in C++, nor is there any way to add them by adding more to the library. In D, they take the obvious syntactical forms:

switch (str)
{
    case "hello":
    case "world":
    ...
}

where str can be any of literal "string"s, fixed string arrays like char[10], or dynamic strings like char[]. A quality implementation can, of course, explore many strategies of efficiently implementing this based on the contents of the case strings.

Filling a String

In C++, this is done with the replace() member function:

string str = "hello";
str.replace(1,2,2,'?');		// str is "h??lo"

In D, use the array slicing syntax in the natural manner:

char[5] str = "hello";
str[1..3] = '?';		// str is "h??lo"

Value vs Reference

C++ strings, as implemented by STLport, are by value and are 0-terminated. [The latter is an implementation choice, but STLport seems to be the most popular implementation.] This, coupled with no garbage collection, has some consequences. First of all, any string created must make its own copy of the string data. The 'owner' of the string data must be kept track of, because when the owner is deleted all references become invalid. If one tries to avoid the dangling reference problem by treating strings as value types, there will be a lot of overhead of memory allocation, data copying, and memory deallocation. Next, the 0-termination implies that strings cannot refer to other strings. String data in the data segment, stack, etc., cannot be referred to.

D strings are reference types, and the memory is garbage collected. This means that only references need to be copied, not the string data. D strings can refer to data in the static data segment, data on the stack, data inside other strings, objects, file buffers, etc. There's no need to keep track of the 'owner' of the string data.

The obvious question is if multiple D strings refer to the same string data, what happens if the data is modified? All the references will now point to the modified data. This can have its own consequences, which can be avoided if the copy-on-write convention is followed. All copy-on-write is is that if a string is written to, an actual copy of the string data is made first.

The result of D strings being reference only and garbage collected is that code that does a lot of string manipulating, such as an lzw compressor, can be a lot more efficient in terms of both memory consumption and speed.

Benchmark

Let's take a look at a small utility, wordcount, that counts up the frequency of each word in a text file. In D, it looks like this:

import std.file;
import std.stdio;

int main (char[][] args)
{
    int w_total;
    int l_total;
    int c_total;
    int[char[]] dictionary;

    writefln("   lines   words   bytes file");
    for (int i = 1; i < args.length; ++i)
    {
    char[] input;
    int w_cnt, l_cnt, c_cnt;
    int inword;
    int wstart;

    input = cast(char[])std.file.read(args[i]);

    for (int j = 0; j < input.length; j++)
    {   char c;

        c = input[j];
        if (c == '\n')
        ++l_cnt;
        if (c >= '0' && c <= '9')
        {
        }
        else if (c >= 'a' && c <= 'z' ||
        c >= 'A' && c <= 'Z')
        {
        if (!inword)
        {
            wstart = j;
            inword = 1;
            ++w_cnt;
        }
        }
        else if (inword)
        {   char[] word = input[wstart .. j];

        dictionary[word]++;
        inword = 0;
        }
        ++c_cnt;
    }
    if (inword)
    {   char[] w = input[wstart .. input.length];
        dictionary[w]++;
    }
    writefln("%8s%8s%8s %s", l_cnt, w_cnt, c_cnt, args[i]);
    l_total += l_cnt;
    w_total += w_cnt;
    c_total += c_cnt;
    }

    if (args.length > 2)
    {
    writefln("--------------------------------------%8s%8s%8s total",
        l_total, w_total, c_total);
    }

    writefln("--------------------------------------");

    foreach (char[] word1; dictionary.keys.sort)
    {
    writefln("%3d %s", dictionary[word1], word1);
    }
    return 0;
}

(An alternate implementation that uses buffered file I/O to handle larger files.)

Two people have written C++ implementations using the C++ standard template library, wccpp1 and wccpp2. The input file alice30.txt is the text of "Alice in Wonderland." The D compiler, dmd, and the C++ compiler, dmc, share the same optimizer and code generator, which provides a more apples to apples comparison of the efficiency of the semantics of the languages rather than the optimization and code generator sophistication. Tests were run on a Win XP machine. dmc uses STLport for the template implementation.

Program | Compile | Compile Time | Run | Run Time
D wc | dmd wc -O -release | 0.0719 | wc alice30.txt >log | 0.0326
C++ wccpp1 | dmc wccpp1 -o -I\dm\stlport\stlport | 2.1917 | wccpp1 alice30.txt >log | 0.0944
C++ wccpp2 | dmc wccpp2 -o -I\dm\stlport\stlport | 2.0463 | wccpp2 alice30.txt >log | 0.1012

The following tests were run on linux, again comparing a D compiler (gdc) and a C++ compiler (g++) that share a common optimizer and code generator. The system is Pentium III 800MHz running RedHat Linux 8.0 and gcc 3.4.2. The Digital Mars D compiler for linux (dmd) is included for comparison.

Program | Compile | Compile Time | Run | Run Time
D wc | gdc -O2 -frelease -o wc wc.d | 0.326 | wc alice30.txt > /dev/null | 0.041
D wc | dmd wc -O -release | 0.235 | wc alice30.txt > /dev/null | 0.041
C++ wccpp1 | g++ -O2 -o wccpp1 wccpp1.cc | 2.874 | wccpp1 alice30.txt > /dev/null | 0.086
C++ wccpp2 | g++ -O2 -o wccpp2 wccpp2.cc | 2.886 | wccpp2 alice30.txt > /dev/null | 0.095

These tests compare gdc with g++ on a PowerMac G5 2x2.0GHz running MacOS X 10.3.5 and gcc 3.4.2. (Timings are a little less accurate.)

Program | Compile | Compile Time | Run | Run Time
D wc | gdc -O2 -frelease -o wc wc.d | 0.28 | wc alice30.txt > /dev/null | 0.03
C++ wccpp1 | g++ -O2 -o wccpp1 wccpp1.cc | 1.90 | wccpp1 alice30.txt > /dev/null | 0.07
C++ wccpp2 | g++ -O2 -o wccpp2 wccpp2.cc | 1.88 | wccpp2 alice30.txt > /dev/null | 0.08

wccpp2 by Allan Odgaard

#include <algorithm>
#include <cstdio>
#include <fstream>
#include <iterator>
#include <map>
#include <vector>

bool isWordStartChar (char c)	{ return isalpha(c); }
bool isWordEndChar (char c)	{ return !isalnum(c); }

int main (int argc, char const* argv[])
{
    using namespace std;
    printf("Lines Words Bytes File:\n");

    map<string, int> dict;
    int tLines = 0, tWords = 0, tBytes = 0;
    for(int i = 1; i < argc; i++)
    {
    ifstream file(argv[i]);
    istreambuf_iterator<char> from(file.rdbuf()), to;
    vector<char> v(from, to);
    vector<char>::iterator first = v.begin(), last = v.end(), bow, eow;

    int numLines = count(first, last, '\n');
    int numWords = 0;
    int numBytes = last - first;

    for(eow = first; eow != last; )
    {
        bow = find_if(eow, last, isWordStartChar);
        eow = find_if(bow, last, isWordEndChar);
        if(bow != eow)
        ++dict[string(bow, eow)], ++numWords;
    }

    printf("%5d %5d %5d %s\n", numLines, numWords, numBytes, argv[i]);

    tLines += numLines;
    tWords += numWords;
    tBytes += numBytes;
    }

    if(argc > 2)
        printf("-----------------------\n%5d %5d %5d\n", tLines, tWords, tBytes);
    printf("-----------------------\n\n");

    for(map<string, int>::const_iterator it = dict.begin(); it != dict.end(); ++it)
        printf("%5d %s\n", it->second, it->first.c_str());

    return 0;
}


D Complex Types vs C++ std::complex

Last update Sun Dec 30 20:34:42 2012

D Complex Types and C++ std::complex

How do D's complex numbers compare with C++'s std::complex class?

Syntactical Aesthetics

In C++, the complex types are:
complex<float>
complex<double>
complex<long double>
C++ has no distinct imaginary type. D has 3 complex types and 3 imaginary types:
cfloat
cdouble
creal
ifloat
idouble
ireal
A C++ complex number can interact with an arithmetic literal, but since there is no imaginary type, imaginary numbers can only be created with the constructor syntax:
complex<long double> a = 5;		// a = 5 + 0i
complex<long double> b(0,7);		// b = 0 + 7i
c = a + b + complex<long double>(0,7);	// c = 5 + 14i
In D, an imaginary numeric literal has the 'i' suffix. The corresponding code would be the more natural:
creal a = 5;		// a = 5 + 0i
ireal b = 7i;		// b = 7i
c = a + b + 7i;		// c = 5 + 14i
For more involved expressions involving constants:
c = (6 + 2i - 1 + 3i) / 3i;
In C++, this would be:
c = (complex<double>(6,2) + complex<double>(-1,3)) / complex<double>(0,3);
or if an imaginary class were added to C++ it might be:
c = (6 + imaginary<double>(2) - 1 + imaginary<double>(3)) / imaginary<double>(3);
In other words, an imaginary number nn can be represented with just nni rather than writing a constructor call complex<long double>(0,nn).

Efficiency

The lack of an imaginary type in C++ means that operations on imaginary numbers wind up with a lot of extra computations done on the 0 real part. For example, adding two imaginary numbers in D is one add:
ireal a, b, c;
c = a + b;
In C++, it is two adds, as the real parts get added too:
c.re = a.re + b.re;
c.im = a.im + b.im;
Multiply is worse, as 4 multiplies and two adds are done instead of one multiply:
c.re = a.re * b.re - a.im * b.im;
c.im = a.im * b.re + a.re * b.im;
Divide is the worst - D has one divide, whereas C++ implements complex division with typically one comparison, 3 divides, 3 multiplies and 3 additions:
if (fabs(b.re) < fabs(b.im))
{
    r = b.re / b.im;
    den = b.im + r * b.re;
    c.re = (a.re * r + a.im) / den;
    c.im = (a.im * r - a.re) / den;
}
else
{
    r = b.im / b.re;
    den = b.re + r * b.im;
    c.re = (a.re + r * a.im) / den;
    c.im = (a.im - r * a.re) / den;
}
To avoid these efficiency concerns in C++, one could simulate an imaginary number using a double. For example, given the D:
cdouble c;
idouble im;
c *= im;
it could be written in C++ as:
complex<double> c;
double im;
c = complex<double>(-c.imag() * im, c.real() * im);
but then the advantages of complex being a library type integrated in with the arithmetic operators have been lost.

Semantics

Worst of all, the lack of an imaginary type can cause the wrong answer to be inadvertently produced. To quote Prof. Kahan:

"A streamline goes astray when the complex functions SQRT and LOG are implemented, as is necessary in Fortran and in libraries currently distributed with C/C++ compilers, in a way that disregards the sign of 0.0 in IEEE 754 arithmetic and consequently violates identities like SQRT( CONJ( Z ) ) = CONJ( SQRT( Z ) ) and LOG( CONJ( Z ) ) = CONJ( LOG( Z ) ) whenever the COMPLEX variable Z takes negative real values. Such anomalies are unavoidable if Complex Arithmetic operates on pairs (x, y) instead of notional sums x + i*y of real and imaginary variables. The language of pairs is incorrect for Complex Arithmetic; it needs the Imaginary type."

The semantic problems are:
  • Consider the formula (1 - infinity*i) * i which should produce (infinity + i). However, if instead the second factor is (0 + i) rather than just i, the result is (infinity + NaN*i), a spurious NaN was generated.
  • A distinct imaginary type preserves the sign of 0, necessary for calculations involving branch cuts.
Appendix G of the C99 standard has recommendations for dealing with this problem. However, those recommendations are not part of the C++98 standard, and so cannot be portably relied upon.

References

How Java's Floating-Point Hurts Everyone Everywhere Prof. W. Kahan and Joseph D. Darcy

The Numerical Analyst as Computer Science Curmudgeon by Prof. W. Kahan

"Branch Cuts for Complex Elementary Functions, or Much Ado About Nothing's Sign Bit" by W. Kahan, ch.
7 in The State of the Art in Numerical Analysis (1987) ed. by M. Powell and A. Iserles for Oxford U.P.


D's Contract Programming vs C++'s

Last update Sun Dec 30 20:34:42 2012

D's Contract Programming vs C++'s

Many people have written me saying that D's Contract Programming (DbC) does not add anything that C++ does not already support. They go on to illustrate their point with a technique for doing DbC in C++.

It makes sense to review what DbC is, how it is done in D, and stack that up with what each of the various C++ DbC techniques can do.

Digital Mars C++ adds extensions to C++ to support DbC, but they are not covered here because they are not part of standard C++ and are not supported by any other C++ compiler.

Contract Programming in D

This is more fully documented in the D Contract Programming document. To sum up, DbC in D has the following characteristics:
  1. The assert is the basic contract.
  2. When an assert contract fails, it throws an exception. Such exceptions can be caught and handled, or allowed to terminate the program.
  3. Classes can have class invariants which are checked upon entry and exit of each public class member function, the exit of each constructor, and the entry of the destructor.
  4. Assert contracts on object references check the class invariant for that object.
  5. Class invariants are inherited, that means that a derived class invariant will implicitly call the base class invariant.
  6. Functions can have preconditions and postconditions.
  7. For member functions in a class inheritance hierarchy, the precondition of a derived class function are OR'd together with the preconditions of all the functions it overrides. The postconditions are AND'd together.
  8. By throwing a compiler switch, DbC code can be enabled or can be withdrawn from the compiled code.
  9. Code works semantically the same with or without DbC checking enabled.

Contract Programming in C++

The assert Macro

C++ does have the basic assert macro, which tests its argument and if it fails, aborts the program. assert can be turned on and off with the NDEBUG macro.

assert does not know anything about class invariants, and does not throw an exception when it fails. It just aborts the program after writing a message. assert relies on a macro text preprocessor to work.

assert is where explicit support for DbC in Standard C++ begins and ends.

Class Invariants

Consider a class invariant in D:
class A
{
    invariant() { ...contracts... }

    this() { ... }	// constructor
    ~this() { ... }	// destructor

    void foo() { ... }	// public member function
}

class B : A
{
    invariant() { ...contracts... }
    ...
}
To accomplish the equivalent in C++ (thanks to Bob Bell for providing this):
template
inline void check_invariant(T& iX)
{
#ifdef DBC
    iX.invariant();
#endif
}

// A.h:

class A {
    public:
#ifdef DBG
       virtual void invariant() { ...contracts... }
#endif
       void foo();
};

// A.cpp:

void A::foo()
{
    check_invariant(*this);
    ...
    check_invariant(*this);
}

// B.h:

#include "A.h"

class B : public A {
    public:
#ifdef DBG
    virtual void invariant()
    {   ...contracts...
       A::invariant();
    }
#endif
       void bar();
};

// B.cpp:

void B::barG()
{
    check_invariant(*this);
    ...
    check_invariant(*this);
}
There's an additional complication with A::foo(). Upon every normal exit from the function, the invariant() should be called. This means that code that looks like:
int A::foo()
{
    ...
    if (...)
    return bar();
    return 3;
}
would need to be written as:
int A::foo()
{
    int result;
    check_invariant(*this);
    ...
    if (...)
    {
    result = bar();
    check_invariant(*this);
    return result;
    }
    check_invariant(*this);
    return 3;
}
Or recode the function so it has a single exit point. One possibility to mitigate this is to use RAII techniques:
int A::foo()
{
#if DBC
    struct Sentry {
       Sentry(A& iA) : mA(iA) { check_invariants(iA); }
       ~Sentry() { check_invariants(mA); }
       A& mA;
    } sentry(*this);
#endif
    ...
    if (...)
    return bar();
    return 3;
}
The #if DBC is still there because some compilers may not optimize the whole thing away if check_invariants compiles to nothing.

Preconditions and Postconditions

Consider the following in D:
void foo()
    in { ...preconditions... }
    out { ...postconditions... }
    body
    {
    ...implementation...
    }
This is nicely handled in C++ with the nested Sentry struct:
void foo()
{
    struct Sentry
    {   Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
    ...implementation...
}
If the preconditions and postconditions consist of nothing more than assert macros, the whole doesn't need to be wrapped in a #ifdef pair, since a good C++ compiler will optimize the whole thing away if the asserts are turned off.

But suppose foo() sorts an array, and the postcondition needs to walk the array and verify that it really is sorted. Now the shebang needs to be wrapped in #ifdef:

void foo()
{
#ifdef DBC
    struct Sentry
    {   Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
#endif
    ...implementation...
}
(One can make use of the C++ rule that templates are only instantiated when used can be used to avoid the #ifdef, by putting the conditions into a template function referenced by the assert.)

Let's add a return value to foo() that needs to be checked in the postconditions. In D:

int foo()
    in { ...preconditions... }
    out (result) { ...postconditions... }
    body
    {
    ...implementation...
    if (...)
        return bar();
    return 3;
    }
In C++:
int foo()
{
#ifdef DBC
    struct Sentry
    {   int result;
    Sentry() { ...preconditions... }
    ~Sentry() { ...postconditions... }
    } sentry;
#endif
    ...implementation...
    if (...)
    {   int i = bar();
#ifdef DBC
    sentry.result = i;
#endif
    return i;
    }
#ifdef DBC
    sentry.result = 3;
#endif
    return 3;
}
Now add a couple parameters to foo(). In D:
int foo(int a, int b)
    in { ...preconditions... }
    out (result) { ...postconditions... }
    body
    {
    ...implementation...
    if (...)
        return bar();
    return 3;
    }
In C++:
int foo(int a, int b)
{
#ifdef DBC
    struct Sentry
    {   int a, b;
    int result;
    Sentry(int a, int b)
    {   this->a = a;
        this->b = b;
        ...preconditions...
    }
    ~Sentry() { ...postconditions... }
    } sentry(a,b);
#endif
    ...implementation...
    if (...)
    {   int i = bar();
#ifdef DBC
        sentry.result = i;
#endif
        return i;
    }
#ifdef DBC
    sentry.result = 3;
#endif
    return 3;
}

Preconditions and Postconditions for Member Functions

Consider the use of preconditions and postconditions for a polymorphic function in D:
class A
{
    void foo()
    in { ...Apreconditions... }
    out { ...Apostconditions... }
    body
    {
        ...implementation...
    }
}

class B : A
{
    void foo()
    in { ...Bpreconditions... }
    out { ...Bpostconditions... }
    body
    {
        ...implementation...
    }
}
The semantics for a call to B.foo() are:
  • Either Apreconditions or Bpreconditions must be satisfied.
  • Both Apostconditions and Bpostconditions must be satisfied.
Let's get this to work in C++:
class A
{
protected:
    #if DBC
    int foo_preconditions() { ...Apreconditions... }
    void foo_postconditions() { ...Apostconditions... }
    #else
    int foo_preconditions() { return 1; }
    void foo_postconditions() { }
    #endif

    void foo_internal()
    {
    ...implementation...
    }

public:
    virtual void foo()
    {
    foo_preconditions();
    foo_internal();
    foo_postconditions();
    }
};

class B : A
{
protected:
    #if DBC
    int foo_preconditions() { ...Bpreconditions... }
    void foo_postconditions() { ...Bpostconditions... }
    #else
    int foo_preconditions() { return 1; }
    void foo_postconditions() { }
    #endif

    void foo_internal()
    {
    ...implementation...
    }

public:
    virtual void foo()
    {
    assert(foo_preconditions() || A::foo_preconditions());
    foo_internal();
    A::foo_postconditions();
    foo_postconditions();
    }
};
Something interesting has happened here. The preconditions can no longer be done using assert, since the results need to be OR'd together. I'll leave as a reader exercise adding in a class invariant, function return values for foo(), and parameters for foo().

Conclusion

These C++ techniques can work up to a point. But, aside from assert, they are not standardized and so will vary from project to project. Furthermore, they require much tedious adhesion to a particular convention, and add significant clutter to the code. Perhaps that's why it's rarely seen in practice.

By adding support for DbC into the language, D offers an easy way to use DbC and get it right. Being in the language standardizes the way it will be used from project to project.

References

Chapter C.11 introduces the theory and rationale of Contract Programming in Object-Oriented Software Construction
Bertrand Meyer, Prentice Hall

Chapters 24.3.7.1 to 24.3.7.3 discuss Contract Programming in C++ in The C++ Programming Language Special Edition
Bjarne Stroustrup, Addison-Wesley


Lisp vs. Java... D?

Last update Sun Dec 30 20:34:43 2012

Lisp vs. Java... D?

by Lionello Lunesu, Oct. 18th 2006

Two weeks ago, Josh Stern posted an interesting link on the digitalmars.D newsgroup. The link pointed to a page describing a programming challenge that was originally used in a study in which 38 C, C++ and Java programmers were asked to write versions of a program to compare Java and C++ efficiency.

Many other programmers had taken up the challenge since. In one such comparison, Lisp turned out to be a clear winner over Java and C++ when comparing development time and lines of code, with the record standing at about 2 hours, with 45 non-comment non-blank lines. For C++, the shortest development time was 3 hours and the shortest program had 107 lines of code.

With some time to spare, I thought I should give it a try myself. Although I'm a C++ programmer myself (and have been for 10 years now), I thought it would be a great opportunity to test my skills in the D programming language.

I had not looked at the other implementations and only read the original problem statement. It took me 1 hour and 15 minutes, from reading the statement to finishing the program. The program was just 55 lines long (remember, the shortest C++ entry had 107 lines), not counting blank lines, comments, assertions, unittests, contracts and trailing curly brackets (similar to Lisp).

The program basically had to do this: read all words from a dictionary file; for each letter there was a corresponding digit (like the letters on a phone); using this mapping, read phone numbers from another text file and print all possible combinations of words for that phone number. Check the link above for more details.

What made implementing this task so easy in D? I just happened to have every construct I needed at hand. Some of the goodies used, are:

  • Assertions, contracts and unittests
  • Built-in arrays and strings, with easy slicing
  • Built-in associative array
  • Garbage collection
  • Type deduction and foreach
  • Nested functions
  • Returning (reference to) a array from a function

During the actual programming I did not have to stop and think about anything. The program evolved automatically, once I thought of the actual container for the dictionary. It turned out that the 'winning' Lisp version was storing the dictionary in a similar manner.

Compiling

To test the program yourself, first download the dictionary.txt and input.txt. Then, download the latest D compiler. To compile, copy-paste the D code into a newly created file phoneno.d, and compile it with:

dmd -run phoneno.d

// Created by Lionello Lunesu and placed in the public domain.
// This file has been modified from its original version.
// It has been formatted to fit your screen.
module phoneno;     // optional
import std.stdio;   // writefln
import std.ctype;   // isdigit
import std.stream;  // BufferedFile

// Just for readability (imagine char[][][char[]])
alias char[] string;
alias string[] stringarray;

/// Strips non-digit characters from the string (COW)
string stripNonDigit( in string line )
{
    string ret;
    foreach(uint i, c; line) {
        // Error: std.ctype.isdigit at C:\dmd\src\phobos\std\ctype.d(37)
        // conflicts with std.stream.isdigit at C:\dmd\src\phobos\std\stream.d(2924)
        if (!std.ctype.isdigit(c)) {
            if (!ret)
                ret = line[0..i];
        }
        else if (ret)
            ret ~= c;
    }
    return ret?ret:line;
}

unittest {
    assert( stripNonDigit("asdf") == ""  );
    assert( stripNonDigit("\'13-=2 4kop") ==  "1324"  );
}

/// Converts a word into a number, ignoring all non alpha characters
string wordToNum( in string word )
{
// translation table for the task at hand
const char[256] TRANSLATE =
    "                                "  // 0
    "                0123456789      "  // 32
    " 57630499617851881234762239     "  // 64
    " 57630499617851881234762239     "
    "                                "
    "                                "
    "                                "
    "                                ";
    string ret;
    foreach(c; cast(ubyte[])word)
        if (TRANSLATE[c] != ' ')
            ret ~= TRANSLATE[c];
    return ret;
}

unittest {
 // Test wordToNum using the table from the task description.
 assert( "01112223334455666777888999" ==
   wordToNum("E | J N Q | R W X | D S Y | F T | A M | C I V | B K U | L O P | G H Z"));
 assert( "01112223334455666777888999" ==
   wordToNum("e | j n q | r w x | d s y | f t | a m | c i v | b k u | l o p | g h z"));
 assert( "0123456789" ==
   wordToNum("0 |   1   |   2   |   3   |  4  |  5  |   6   |   7   |   8   |   9"));
}

void main( string[] args )
{
    // This associative array maps a number to an array of words.
    stringarray[string]    num2words;

    foreach(string word; new BufferedFile("dictionary.txt" ) )
        num2words[ wordToNum(word) ] ~= word.dup;        // must dup

    /// Finds all alternatives for the given number
    /// (should have been stripped from non-digit characters)
    stringarray _FindWords( string numbers, bool digitok )
    in {
        assert(numbers.length >  0);
    }
    out(result) {
        foreach (a; result)
            assert( wordToNum(a) == numbers );
    }
    body {
        stringarray ret;
        bool foundword = false;
        for (uint t=1; t<=numbers.length; ++t) {
            auto alternatives = numbers[0..t] in num2words;
            if (!alternatives)
                continue;
            foundword = true;
            if (numbers.length >  t) {
                // Combine all current alternatives with all alternatives
                // of the rest (next piece can start with a digit)
                foreach (a2; _FindWords( numbers[t..$], true     ) )
                    foreach(a1; *alternatives)
                       ret ~= a1 ~ " " ~ a2;
            }
            else
                ret ~= *alternatives;    // append these alternatives
        }
        // Try to keep 1 digit, only if we're allowed and no other
        // alternatives were found
        // Testing "ret.length" makes more sense than testing "foundword",
        // but the other implementations seem to do just this.
        if (digitok && !foundword) { //ret.length == 0
            if(numbers.length >  1) {
                // Combine 1 digit with all altenatives from the rest
                // (next piece can not start with a digit)
                foreach (a; _FindWords( numbers[1..$], false ) )
                    ret ~= numbers[0..1] ~ " " ~ a;
            }
            else
                ret ~= numbers[0..1];    // just append this digit
        }
        return ret;
    }

    /// (This function was inlined in the original program)
    /// Finds all alternatives for the given phone number
    /// Returns: array of strings
    stringarray FindWords( string phone_number )
    {
        if (!phone_number.length)
            return null;
        // Strip the non-digit characters from the phone number, and
        // pass it to the recursive function (leading digit is allowed)
        return _FindWords( stripNonDigit(phone_number), true );
    }

    // Read the phone numbers
    foreach(string phone; new BufferedFile("input.txt"   ) )
        foreach(alternative; FindWords( phone ) )
            writefln(phone, ": ", alternative );
}

Forums | Comments | D | Search | Downloads | Home
| Page generated by Ddoc.


Digital Mars - The D Programming Language

 [Home] [Search] [D]

Title

Copyright (c) 1999-2001 by Digital Mars, All Rights Reserved


Change Log

Last update Sun Dec 30 20:34:43 2012

D Change Log to Nov 7 2005

  • What's new for D 0.139
  • What's new for D 0.138
  • What's new for D 0.137
  • What's new for D 0.136
  • What's new for D 0.135
  • What's new for D 0.134
  • What's new for D 0.133
  • What's new for D 0.132
  • What's new for D 0.131
  • What's new for D 0.130
  • What's new for D 0.129
  • What's new for D 0.128
  • What's new for D 0.127
  • What's new for D 0.126
  • What's new for D 0.125
  • What's new for D 0.124
  • What's new for D 0.123
  • What's new for D 0.122
  • What's new for D 0.121
  • What's new for D 0.120
  • What's new for D 0.119
  • What's new for D 0.118
  • What's new for D 0.117
  • What's new for D 0.116
  • What's new for D 0.115
  • What's new for D 0.114
  • What's new for D 0.113
  • What's new for D 0.112
  • What's new for D 0.111
  • What's new for D 0.110
  • What's new for D 0.109
  • What's new for D 0.108
  • What's new for D 0.107
  • What's new for D 0.106
  • What's new for D 0.105
  • What's new for D 0.104
  • What's new for D 0.103
  • What's new for D 0.102
  • What's new for D 0.101
  • What's new for D 0.100
  • What's new for D 0.99
  • What's new for D 0.98
  • What's new for D 0.97
  • What's new for D 0.96
  • What's new for D 0.95
  • What's new for D 0.94
  • What's new for D 0.93
  • What's new for D 0.92
  • What's new for D 0.91
  • What's new for D 0.90
  • What's new for D 0.89
  • What's new for D 0.88
  • What's new for D 0.86
  • What's new for D 0.82
  • What's new for D 0.81
  • What's new for D 0.80
  • What's new for D 0.79
  • What's new for D 0.78
  • What's new for D 0.77
  • What's new for D 0.76
  • What's new for D 0.75
  • What's new for D 0.74
  • What's new for D 0.73
  • What's new for D 0.72
  • What's new for D 0.71
  • What's new for D 0.70
  • What's new for D 0.69
  • What's new for D 0.68
  • What's new for D 0.67
  • What's new for D 0.66
  • What's new for D 0.65
  • What's new for D 0.64
  • What's new for D 0.63
  • What's new for D 0.61
  • What's new for D 0.59
  • What's new for D 0.58
  • What's new for D 0.57
  • What's new for D 0.56
  • What's new for D 0.55
  • What's new for D 0.54
  • What's new for D 0.53
  • What's new for D 0.52
  • What's new for D 0.51
  • What's new for D 0.50
  • What's new for D 0.49
  • What's new for D 0.48
  • What's new for D 0.47
  • What's new for D 0.46
  • What's new for D 0.45
  • What's new for D 0.44
  • What's new for D 0.43
  • What's new for D 0.42
  • What's new for D 0.41
  • What's new for D 0.40
  • What's new for D 0.39
  • What's new for D 0.38
  • What's new for D 0.37
  • What's new for D 0.36
  • What's new for D 0.35
  • What's new for D 0.34
  • What's new for D 0.32
  • What's new for D 0.30
  • What's new for D 0.29
  • What's new for D 0.28
  • What's new for D 0.27
  • What's new for D 0.26
  • What's new for D 0.25
  • What's new for D 0.24
  • What's new for D 0.23
  • What's new for D 0.22
  • What's new for D 0.20
  • What's new for D 0.19
  • What's new for D 0.16
  • What's new for D 0.15
  • What's new for D 0.11
  • What's new for D 0.10
  • What's new for D 0.07
  • What's new for D 0.04
  • What's new for D 0.03
  • What's new for D 0.02
  • What's new for D 0.01
  • What's new for D 0.00
  • Download D compiler for Win32 and x86 linux
  • tech support

What's New for D 0.139

Nov 7, 2005

Bugs Fixed

  • Fixed D.bugs/5329
  • Fixed D.bugs/5330

What's New for D 0.138

Nov 2, 2005

New/Changed Features

  • Implemented constant folding of "string"[constant].
  • Implemented constant folding of "string"[constant .. constant].
  • Added --help switch.
  • Removed std.math2.poly, use std.math.poly instead.
  • Implemented Jarrett Billingsley's suggestion for custom wrappers around structs, modules, etc. D.announce/1705.

Bugs Fixed

  • Fixed D.learn/2070
  • Fixed D.bugs/5202
  • Fixed std.math.lgamma and tgamma.
  • Fixed D.announce/1730
  • Fixed D.bugs/5198
  • Fixed D.bugs/5199
  • Fixed Linux C ABI compatibility bug with returning structs from extern (C) functions. this can break existing code.

What's New for D 0.137

Oct 24, 2005

New/Changed Features

  • Added implicit type inference.
  • extern storage class for variables now works.
  • extern(linkage) for nested functions now works.

Bugs Fixed

  • Fixed grammar per Unknown W. Brackets' suggestions D.bugs/5137 and D.bugs/5147
  • Fixed D.bugs/4862
  • Fixed D.bugs/4972
  • Fixed D.bugs/5098
  • Fixed D.bugs/5172
  • Fixed D.gnu/1472
  • Fixed D.bugs/5171

What's New for D 0.136

Oct 17, 2005

New/Changed Features

  • Added Doc Clugston's D/28800 for tgamma, lgamma.
  • Updated std.md5 per Dawid Ciezarkiewicz's suggestion D/28887.

Bugs Fixed

  • Fixed D.bugs/4533
  • Fixed D.bugs/4769
  • Fixed D.bugs/4882
  • Fixed D.bugs/4985
  • Fixed D.bugs/5015
  • Fixed D.bugs/5016
  • Fixed D.bugs/5076
  • Fixed D.bugs/5082
  • Fixed D.bugs/5083
  • Fixed D.bugs/5111
  • Fixed D.bugs/5115
  • Fixed D.bugs/5130
  • Fixed D.bugs/5143

What's New for D 0.135

Oct 2, 2005

New/Changed Features

  • Color syntax highlighting is here!
  • Added capability to process general purpose documents.

Bugs Fixed

  • Fixed D/28888

What's New for D 0.134

Sep 28, 2005

New/Changed Features

  • Added .. macro arguments, and special macro.
  • Each standard section now has its own custom DDOC_ macro.
  • Incorporated Bob W's suggestions D/28843.

Bugs Fixed

  • Fixed bug where .ddoc files needed to end in newline.
  • Fixed D.announce/1563
  • Fixed D.announce/1598

What's New for D 0.133

Sep 24, 2005

New/Changed Features

  • Filled out std.math with standard C math.h functions.
  • Added -o- flag to suppress generation of object file.
  • Removes closing *'s on /******* Comment ***********/
  • '_' in section names now replaced with ' ' (Derek Parnell's idea).
  • Extensive revision to how macros work based on a suggestion from Derek Parnell. Much more flexible now.

Bugs Fixed

  • Fixed D.bugs/5045
  • Fixed D.announce/1564

What's New for D 0.132

Sep 19, 2005

New/Changed Features

  • Added Ddoc, the documentation generator for D.

What's New for D 0.131

Sep 8, 2005

Bugs Fixed

  • Fixed problem with Linux line number generation.
  • Fixed D.announce/1467
  • Fixed D.announce/1483

What's New for D 0.130

Sep 6, 2005

New/Changed Features

  • Added Don Clugston's std.math.feqrel().
  • Added Ben Hinkle's updates to std.stream:
    • removed all deprecated features stdin/out/err and the Error exceptions D/27364
    • new FilterStream superclass of BufferedStream, EndianStream and SliceStream
    • added File.available overload D/27684
    • Fixed D.bugs/4711
    • updated html doc with more details about filtering D.announce/1102
  • Added Ben Hinkle's updates to std.mmfile from thread D.bugs/4550
    • added windowing support
    • changed size parameters to ulong instead of size_t
    • commented out the debug printf
    • added unittests
    • updated help

Bugs Fixed

  • Fixed D.bugs/4684
  • Fixed D.bugs/4634
  • Fixed D.bugs/4818
  • Fixed D.bugs/4696
  • Fixed D.bugs/4750
  • Fixed D.bugs/4699
  • Fixed D.bugs/4726
  • Fixed D.bugs/4761
  • Fixed D.bugs/4765
  • Fixed D.bugs/4768
  • Fixed DMDScript/4768

What's New for D 0.129

Aug 5, 2005

New/Changed Features

  • Added postfixes c, w, d to string literals to denote type.
  • For linux, DW_LANG_D is used for DW_AT_language in the Dwarf symbolic debug info. If the -gc switch is used, DW_LANG_C is used for older GDB's.
  • Incorporated Ben Hinkle's new std.format which can print general arrays.
  • Added std.stdio.writefx and std.stream.writefx from David L. Davis and Ben Hinkle.
  • Incorporated Ameer Armaly's improvement to std.c.linux.linux D/27320.

Bugs Fixed

  • Implemented access checking for structs.
  • Fixed D.bugs/4555

What's New for D 0.128

Jul 10, 2005

New/Changed Features

  • Incorporated Ameer Armaly's improvement to std.file.exists() D/26226.
  • Ben Hinkle's update for stream.d and std_stream.html: As discussed in D/26073 scanf and vscanf have been modified and renamed to readf and vreadf (with doc updates, too).

Bugs Fixed

  • Ben Hinkle's fix for D.bugs/4335. In particular the doc for readLine is fixed. The return type of writef and writefln is fixed.
  • Fixed D/26224
  • Fixed D.bugs/4472
  • Fixed D.bugs/4377
  • Fixed D.bugs/4409
  • Fixed D.bugs/4296
  • Fixed D.bugs/4382
  • Fixed D.bugs/4386
  • Fixed D.bugs/4396
  • Fixed D.bugs/4398
  • Fixed D.bugs/4413
  • Applied buffer overflow fix to etc/c/zlib/inftrees.c.

What's New for D 0.127

Jun 16, 2005

New/Changed Features

  • No more forward references of version or debug identifiers.

Bugs Fixed

  • Fixed D.bugs/4185
  • Fixed D.bugs/4246
  • Fixed D.bugs/4239
  • Fixed D.bugs/4249
  • Fixed D.bugs/4299
  • Fixed D.bugs/4153
  • Fixed D.bugs/4161
  • Fixed D.bugs/4240
  • Fixed D.bugs/4248
  • Fixed D.bugs/4300
  • Fixed D.learn/1073

What's New for D 0.126

Jun 7, 2005

New/Changed Features

  • === now deprecated, replaced with is.
  • !== now deprecated, replaced with !is.
  • Added typesafe variadic functions.
  • Now throws an ArrayBoundsError if accessing an associative array with a key that is not already in the array. Previously, the key would be added to the array.
  • Added s which replaces IftypeConditions which are now deprecated. The IsExpressions are significantly more general and powerful.
  • Added VoidInitializers.
  • delete aa[key] is now deprecated, use aa.remove(key) instead.
  • Added non-static nested classes.
  • Added anonymous non-static nested classes.
  • Incorporated Ben Hinkle's changes to std.stream:
    • std.stream.stdin/out/err deprecated
    • adding std.cstream.din/out/err
    • stream.d:
      • incorporate the socketstream code for handling \r end-of-line formats for readLine on non-seekable streams like pipes
      • getc and getcw return char.init and wchar.init on EOF
      • getcw throws if EOF after reading 1 byte
      • ungetc and ungetcw ignore char.init and wchar.init
      • deprecate stdin,stdout,stderr
      • remove private import of std.c.stdio and aliases for va_list
    • socketstream.d: removed overrides that are now in std.stream.Stream
    • cstream.d: new stream wrapper around FILE* with din, dout, derr
    • unittest,d: add cstream to ensure unittests are run

Bugs Fixed

  • Fixed Internal error: e2ir.c 488
  • Incorporated David Friedman's patch for std.base64.
  • Fixed D.bugs/4178
  • Incorporated evilmrhenry's fixes from D.bugs/4215
  • Fixed std.math.tan's bug where it could leave an operand on the FPU stack

What's New for D 0.125

May 20, 2005

Bugs Fixed

  • iftype fixed to do implicit conversion match with specialization, rather than exact match.
  • Fixed D.bugs/4075
  • Ben Hinkle fixed D.learn/873
  • phobos/internal/gc _d_newarrayi() fixed to use std.c.stdarg.

What's New for D 0.124

May 19, 2005

New/Changed Features

  • Added -quiet switch to dmd.
  • .size property is no longer deprecated, it is an error. Replace with .sizeof.
  • Renamed DMD source debcond.h to cond.h, debcond.c to cond.c.
  • Added Burton Radons' std.boxer.
  • Reformatted the documentation to use a bit of color.
  • Added static if.
  • Added iftype.

Bugs Fixed

  • #line broken & fixed again.
  • Fixed compiler crash with modulo 0 arithmetic.
  • Ben Hinkle fixed D.bugs/3982
  • Fixed D.bugs/3981
  • Fixed D.bugs/3968
  • Fixed D.bugs/3975
  • Fixed D.bugs/3999

What's New for D 0.123

May 11, 2005

New/Changed Features

  • Capped static array size at 16Mb.

Bugs Fixed

  • __LINE__ now works as argument to #line.
  • Members are no longer allowed to be named 'alignof'.
  • Added some missing line numbers to error messages.
  • Fixed another circular interface inheritance problem.
  • Fixed internal error cod1 2433
  • Fixed internal error cgcs 353
  • Fixed dstress auto_07
  • Fixed dstress array_initialization_06
  • Fixed dstress array_initialization_08
  • Fixed dstress array_initialization_10
  • Fixed dstress typeid_13
  • Fixed D.bugs/2162
  • Fixed D.bugs/3386
  • Fixed D.bugs/3571
  • Fixed D.bugs/3691
  • Fixed D.bugs/3712
  • Fixed D.bugs/3713
  • Fixed D.bugs/3791
  • Fixed D.bugs/3792
  • Fixed D.bugs/3812
  • Fixed D.bugs/3818
  • Fixed D.bugs/3844
  • Fixed D.bugs/3896
  • Fixed D.bugs/3897
  • Fixed D.bugs/3898
  • Fixed D.bugs/3900

What's New for D 0.122

May 3, 2005

New/Changed Features

  • Added Ben Hinkle's fixes for std.stream:
    • fixes the seekable bugs on reading stdin and pipes
    • adds isOpen and eof to InputStream
    • adds isOpen, flush and close to OutputStream
  • Added std.conv.toFloat, toDouble, toReal from David L. Davis.

Bugs Fixed

  • Improved line numbers in error messages.
  • Fixed problems detecting array overflows at compile time.
  • Improved handling of compiler out-of-memory errors.
  • Fixed DMDScript build break.
  • Fixed memory corruption problem with array[length..length].
  • Fixed compiler seg fault on uplevel invariant.
  • Fixed problem detecting circular interface hierarchies.
  • Fixed cat of static arrays.
  • Fixed Internal error cg87 1240.
  • Fixed D.bugs/3710
  • Fixed D.bugs/3747
  • Fixed D.bugs/3752
  • Fixed D.bugs/3753

What's New for D 0.121

Apr 15, 2005

New/Changed Features

  • std.syserror is now deprecated, replaced with std.windows.syserror. It is Windows specific, and lining it up with strerror() on Linux was a mistake. Windows error numbers do not line up with C's errno values. Thanks to Regan Heath for a decent implementation of it.
  • Now ?: works with null and arrays.
  • Changed std.outofmemory.OutOfMemory to std.outofmemory.OutOfMemoryException, and it now derives from Exception.
  • Abstract class methods now cause the class to be abstract.
  • Abstract can no longer be applied to variables, structs or unions.
  • Unit tests now allowed in structs and unions.

Bugs Fixed

  • Added zwang's fix for std.string.ifind().
  • Fixed constant fold divide by 0.
  • Fixed "Win32 Exception" in std.regexp.
  • Fixed bogus "switch statement already has a default" bug.
  • Fixed D.bugs/2991
  • Fixed D.bugs/3002
  • Fixed D.bugs/3034
  • Fixed D.bugs/3091
  • Fixed D.bugs/3129
  • Fixed D.bugs/3551
  • Fixed D.bugs/3597
  • Fixed D.bugs/3646
  • Implemented typeinfo's for arrays, static arrays, associative arrays, function pointers, delegates, and enums.
  • Fixed typeinfo for typedef's.
  • Fixed broken implicit conversion from real or imaginary to complex.
  • Fixed pragma error messages.
  • Fixed broken pragma(lib) inside function.
  • Fixed dstress slice_10.
  • Fixed dstress argument_03.
  • Fixed dstress const_04.
  • Fixed dstress foreach_26.
  • Fixed dstress html_empty_entity_03.
  • Fixed dstress invariant_12.
  • Fixed dstress invariant_29, _30, _31.
  • Fixed dstress main_06.
  • Fixed dstress mixin_09.
  • Fixed dstress new_09.
  • Incorporated Ben Hinkle's fixes for std.stream. Fixed a bug introduced in dmd-120: D.bugs/3563 about seekable stdin and Stream.toString(). Fixed a bug in the Windows version of seek() with files larger than uint.sizeof.

What's New for D 0.120

Apr 6, 2005

New/Changed Features

  • In -release builds implicit switch defaults, implicit return statements, and assert(0) expressions are replaced with HLT instructions.
  • Renamed -gt command line switch that invokes the profiler to -profile.
  • Complex types can no longer be implicitly converted to non-complex types.
  • Real and imaginary types can no longer be implicitly converted to each other.
  • Added Pentium 4 (Prescott) instructions to inline assembler.
  • Template alias parameters can now have specializations.
  • Compiler now permitted to retain floating point literals and do constant folding on them in a precision that is greater than the precision of its type.
  • Changed AMD64 predefined version to X86_64.
  • Added Matthew Wilson's std.openrj.
  • Ben Hinkle submitted a new std.stream with:

    • replace uint buffer lengths with size_t
    • add line-by-line opApply to Stream and InputStream (due to Regan Heath)
      int opApply(int delegate(inout char[] line) dg)
      int opApply(int delegate(inout ulong n, inout char[] line) dg)
      int opApply(int delegate(inout wchar[] line) dg)
      int opApply(int delegate(inout ulong n, inout wchar[] line) dg)
    • move readable/writeable/seekable tests from contracts to the body since phobos is compiled in release mode and users can easily try to write to an unwritable stream
    • return "this" from writef and writefln to allow chaining (eg flush)
    • fix TArrayStream read/write to check for "eof" (Derick Eddington)
    • make SliceStream preserve the source buffer position if seekable and pay attention to isOpen (Derick)
    • implement available() for more stream types (Derick)
    • copyFrom bug fixes and position preserving if seekable (Derick)
    • move the initialization of the BOMs to the initializer instead of the module constructor.
    • make isopen protected (from private) so that subclasses can see it.
    • more unittest (Derick and Ben)
    • fix File.size() bug on Windows
    • fix File.open() error message to say "Cannot open or create file"

Bugs Fixed

  • Fixed crash with forward reference of local as mixin alias parameter.
  • Fixed bit array append.
  • Fixed base class fwd ref bug introduced in 0.119.
  • Fixed problems with throwing in a destructor.
  • Fixed problem with misaligned arrays of structs.
  • Fixed diagnosis of types based on deprecated symbols.
  • Fixed bad code gen for PEXTRW instruction.
  • Fixed compiler hang with template alias parameters.
  • Fixed Internal error: ..\ztc\cg87.c 279
  • Fixed Internal error: ..\ztc\cod1.c 1648
  • Fixed Internal error: ..\ztc\cgobj.c 2139
  • Fixed Internal error: ..\ztc\cgcs.c 353
  • Fixed Assertion failure 622 glue.c
  • Fixed compiler crash on circular typedef declarations.
  • Fixed compiler crash on empty catch handlers.
  • Fixed D.bugs/2606
  • Fixed D.bugs/2618
  • Fixed D.bugs/3234
  • Fixed D.bugs/3369

What's New for D 0.119

Mar 18, 2005

New/Changed Features

  • Clarified and revamped handling of 'finally' blocks.
  • C-style casts are no longer deprecated, they are now illegal.
  • Invalid UTF sequences in comments are now diagnosed as errors.
  • Can no longer set predefined versions.

Bugs Fixed

  • Fixed &lsaquo; misspelled entity.
  • Fixed parsing entities with digits.
  • Class invariant calls no longer attached to private, protected, or package member functions.
  • Fixed D.bugs/32
  • Fixed D.bugs/1148
  • Fixed D.bugs/1815
  • Fixed D.bugs/1865
  • Fixed D.bugs/1953
  • Fixed D.bugs/2042
  • Fixed D.bugs/2140
  • Fixed D.bugs/2240
  • Fixed D.bugs/2262
  • Fixed D.bugs/2429
  • Fixed D.bugs/2546
  • Fixed D.bugs/2934
  • Changed documentation on struct/union grammar to allow invariants, unit tests, and allocator/deallocators.
  • The file names printed out by runtime assert failures now matches what was set by any preceding #line LineNumber FileName.
  • Fixed bug with aliases as struct members.
  • Error now diagnosed when override is applied to non- class member functions.
  • Fixed colliding template struct initializer problem under Linux.
  • Can now cat string literals to wchar[] or dchar[].
  • Now correctly diagnoses as an error attempts to access members of outer aggregate from within inner aggregate.
  • Fixed Assertion failure: 'cd' on line 1275 in file 'expression.c'
  • Now diagnoses error when catches are 'hidden' by previous catch parameters.
  • Added missing typeid's for void, void[] and bit[].

What's New for D 0.118

Mar 12, 2005

Bugs Fixed

  • Fixed introduced name mangling bug.
  • Fixed introduced bug with COMDAT records.

What's New for D 0.117

Mar 10, 2005

New/Changed Features

  • Added pragma(lib, "library name");
  • cent and ucent are now keywords, to ensure they stay reserved.
  • version=all cannot be explicitly set; all is always on anyway.

Bugs Fixed

  • Fixed spurious unreachable code warning.
  • Now issues error for declaring non-virtual functions as abstract.
  • Declaring an entire class as abstract now works.
  • Added wprintf back to std.c.stdio.
  • Instantiating deprecated classes now generates deprecation message.
  • Fixed several cases where deprecated symbol uses were not flagged.
  • Can now goto case into enclosing switch case.
  • Fixed problem with goto into if(0) block.
  • Incorporated Stewart Gordon's fix for std.file.copy().
  • Fixed Assertion failure: '0' on line 720 in file 'statement.c'
  • Fixed D.bugs/1795
  • Fixed D.bugs/2737
  • Fixed D.bugs/752
  • Fixed D.bugs/1326
  • Fixed D.bugs/2238
  • Fixed D.bugs/2275
  • Fixed D.bugs/2315
  • Fixed D.bugs/2316

What's New for D 0.116

Mar 7, 2005

New/Changed Features

  • Added named character entities to escape sequences.
  • Added much better named character entity support to HTML preprocessing.
  • Added __FILE__, __LINE__, __DATE__, __TIME__, __TIMESTAMP__.
  • $ can now be used instead of length inside an array's []. It represents the length of the array. This is a trial feature, if it works out then these will happen in sequential releases:
    1. length will become deprecated inside [].
    2. length will be removed as the implicitly declared length, and it will be just another identifier.
  • Added warnings on a trial basis.
  • If a module statement name is used with a package prefix, as in:
        module foo.bar;
    then bar is not in scope, one must use foo.bar.

Bugs Fixed

  • Fixed several errors in HTML preprocessing - entities, line numbers, spaces, casing.
  • Fixed mac line termination.
  • Fixed D.gnu/983
  • Fixed D.bugs/1849
  • Added missing typeid's for arrays of floating point types.
  • .sort property now works on arrays of bits and NaNs.
  • Can now return an expression from a function returning void.
  • Can have a main() as a nested function.

What's New for D 0.115

Feb 28, 2005

Bugs Fixed

  • Fixed my bungled integration of std.socket.

What's New for D 0.114

Feb 27, 2005

New/Changed Features

  • Renamed std.regexp.RegExp.search to std.regexp.RegExp.find to be analogous to names in std.string. Old name remains as a deprecated alias.
  • Added functions split, find, rfind, sub, search to std.regexp.
  • Added functions tr, succ, squeeze, removechars, countchars, inPattern, chop, and chomp to std.string.
  • Incorporated Christopher E. Miller's fixes to std.socket:

    IPv6 not supported but the C interface for it should all be there. Split up socket.d and put the C stuff in std.c modules. std.c.linux.linux updated because most of the socket functions are actually regular I/O functions. Added classes Protocol and Service. Added Socket.accepting() to allow derived classes to be accepted. Documentation and samples updated. Fixed major bug in the linux version.

  • Improved error message for overloaded function mismatches.
  • Added man pages to \dmd\man\man1 (thanks to Anders F Bjorklund)

Bugs Fixed

  • Fixed std.format %A unittest failure under linux
  • Fixed proxy static constructor ordering problem.
  • Fixed bug where v.init would initialize v.
  • Fixed .reverse bug of char[] and wchar[] with multibyte encodings.
  • Fixed various problems with constant folding for const initializers.
  • Fixed Internal error: ../ztc/cod4.c 352
  • Fixed Assertion failure: 'ta' on line 1481 in file 'template.c'
  • Fixed Assertion failure: 'f' on line 3005 in file 'expression.c'
  • Fixed Assertion failure: 'ids->vthis' on line 394 in file 'inline.c'
  • Fixed Assertion failure: '0' on line 909 in file 'func.c'
  • Fixed Assertion failure: '!scopesym || !scopesym->isWithScopeSymbol()' on line 2637 in file 'mtype.c'
  • Fixed Assertion failure: 'se2->op == TOKstring' on line 1379 in file 'expression.c'
  • Fixed Assertion failure: '!needThis()' on line 139 in file 'tocsym.c'

What's New for D 0.113

Feb 12, 2005

New/Changed Features

  • internal/qsort2.d is now a freely redistributable version of internal/qsort.d.
  • Added std.file.copy
  • Asserts enabled in release builds if -unittest is given.

Bugs Fixed

  • Fixed cgcs 353 error
  • Fixed dmd crash on class C{this(){super();}}
  • Fixed dmd crash on cast(int)(.0>>0)
  • Fixed dmd crash on enum e;
  • Fixed dmd crash on 0==Exception;
  • Fixed dmd crash on varargs in initializer
  • Fixed dmd crash on labeled {} statements
  • Fixed dmd crash on mishandled forward reference
  • Fixed Internal error: e2ir.c 229
  • Fixed Internal error: ..\ztc\cgcod.c 1640
  • Fixed Internal error: e2ir.c 141
  • Fixed Internal error: ../ztc/elfobj.c 1251
  • Fixed Assertion failure: '!needThis()' on line 139 in file 'tocsym.c'
  • Fixed Assertion failure: 'fdx->vresult' on line 1450 in file 'statement.c'
  • Fixed Assertion failure: '!deferred.dim' on line 470 in file 'module.c'
  • Fixed Assertion failure: 'sym->memtype' on line 3020 in file 'mtype.c'
  • Fixed infamous std.string.toStringz() bug.

What's New for D 0.112

Jan 26, 2005

New/Changed Features

  • Note: This is a library only change, the dmd executables are still at 0.111.
  • New capabilities for making Windows DLLs.
  • The -gt profiler now works under Linux.

What's New for D 0.111

Jan 15, 2005

New/Changed Features

  • Added std.date.toUTCString().
  • \uFFFE and \uFFFF are now allowed as valid UCS characters, since there are applications that use them.
  • Added std.string.toString(long, uint) and toString(ulong, uint) for radix conversions.
  • Incorporated Phobos improvements provided by Ben Hinkle:

    I've attached modified versions of std.stream and mmfile and the help section for std.mmfile and std.stream. The std.mmfile changes are:

    • change module declaration to std.mmfile
    • change class declaration to not be auto
    • add mMode read-only property to get the file mode of type MmFile.Mode
    The std.stream changes are:
    • added Dave Fladebo's performance improvements for buffered readLine
    • fixed a bug in read/write cfloat/cdouble/creal endian support
    • uncommented MmFileStream and cleaned it up to use MmFile's mode property.

Bugs Fixed

  • Fixed .length bug in std.string.sformat().
  • Fixed rounding error in std.date for dates before 1970.
  • Fixed bugs with function inlining and length property.
  • Compensated for errors in linux's powl() function.
  • Fixed rounding problem with convering doubles to ulongs.
  • Extended range of std.date daylight savings time calculation under linux.

What's New for D 0.110

Dec 30, 2004

New/Changed Features

  • Structs can now be forward referenced.
  • Structs can now be used as keys in associative arrays.
  • Arrays of structs can now be sorted.
  • Drastically speedup up compiler with projects that contain complicated imports.
  • Does a better job soldiering on after errors are diagnosed.
  • .sizeof property can no longer be overridden.

Bugs Fixed

  • Fixed regression on using super or this outside of a class.
  • Fixed internal error cod1 2729.
  • Object file now deleted if compilation errors occurred.
  • Fixed some circumstances where properties were not recognized.
  • Fixed potential hang in critical section release code.
  • Fixed pointer value returned by 'in' expressions.
  • Fixed codegen bug with some array initializations.
  • Fixed access violation in std.uri.encodeComponent().

What's New for D 0.109

Dec 5, 2004

New/Changed Features

  • super.id and this.id now work if id does not need a 'this' pointer.

Bugs Fixed

  • Fixed constant folding problem with complex numbers.
  • Fixed class member initialize bug.
  • Fixed compiler gpf on bit sizeof.
  • Now correctly diagnoses some forward reference errors.
  • Fixed error recovery on minusing template as a variable.
  • Fixed internal error e2ir 1158
  • Fixed Assertion failure: '0' on line 661 in file 'expression.c'
  • Fixed synchronized property call omitting ().

What's New for D 0.108

Nov 30, 2004

Bugs Fixed

  • Fixed mango build break.

What's New for D 0.107

Nov 29, 2004

New/Changed Features

  • Improved speed of writef().
  • Improved single thread performance of gc allocation per Dave Fladebo's suggestions.
  • InExpressions now, instead of returning a bit, return a pointer to the associative array element if the key is present, null if it is not. This obviates the need for many double lookups.
  • .offset property is now deprecated, use .offsetof instead. This makes for better compatibility with C and fewer conflicts with offset as a field name.
  • Added .ptr property to arrays, which is handier and more typesafe than casting an array to a pointer.
  • Added Ben Hinkle's changes to std.stream:
    1. adds EndianStream for BOM and endian support.
    2. removes the two public imports std.string and std.file from end of file
    3. adds read/write for ifloat, idouble, cfloat, cdouble and dchar to interfaces InputStream and OutputStream and add implementations to Stream and EndianStream
  • Added std.c.stddef for definition of C wchar_t.

Bugs Fixed

  • Fixed internal error e2ir 814
  • Fixed protection of implicit constructor.
  • Fixed deprecated attribute overriding static.
  • Tightened up detection of constants being implicitly converted to a type that cannot hold it.
  • Now detects duplicate case strings in switch statements.
  • Added support for switch(dchar[]) statements.
  • Fixed bug reading source files without B.O.M.
  • Fixed initialization of anonymous structs in classes.
  • Anonymous structs/unions can now only be a member of an aggregate.
  • Assert expressions are no longer evaluated for side effects even if asserts are turned off. It is not legal to depend on the side effect of an assert.
  • Fixed _init vs __init prefix for TypeInfo classes.
  • Adjusted arithmetic conversion rules to match C99.

What's New for D 0.106

Nov 9, 2004

New/Changed Features

  • Changed std.c.time.CLOCKS_PER_SEC from 1000 to 1000000 for linux.
  • Added version identifier all being always set.
  • Setting one of the list of predefined version identifiers is now an error.
  • Changed TypeInfoClass to TypeInfo_Class.
  • Changed TypeInfoTypedef to TypeInfo_Typedef.
  • Incorporated Matthew Wilson's changes to std.process.

Bugs Fixed

  • Fixed internal error s2ir 458
  • Fixed Assertion failure: 64 tocvdebug.c
  • Fixed codegen error with EAX parameter.
  • Version switch syntax checking fixed.
  • Fixed cast of constant to bit.
  • Multiple declarations of the same type alias now detected.
  • Access check now done for private constructor in new expression.
  • Anonymous structs/unions can now have non-field members.
  • Non-top level classes now added to module class list.
  • Fixed bugs in std.format with class objets, typedefs, %o and %b formats.
  • Fixed optimizer bug with loop invariants.
  • Fixed synchronized statements on Linux.

What's New for D 0.105

Oct 28, 2004

New/Changed Features

  • Changed integral literal type determination to match C99 6.4.4.1.

Bugs Fixed

  • Incorporated David Friedman's fixes for static initializers.
  • Incorporated David Friedman's fixes for bit array duping and array appending.
  • Incorporated David Friedman's fix for cast of integral constant to bit.
  • Incorporated Stewart Gordon's fix for switcherr.d and array.d.
  • Fixed several bugs with dmd command line parsing.
  • Fixed Assertion failure: 'ei' line 2576 file 'mtype.c'
  • Fixed Ivan Senji's two compiler crashes.
  • Fixed Internal error: ..\ztc\cod3.c 736
  • Fixed diagnostic on forward referenced templates.
  • Fixed diagnostic on missing identifiers in foreach declarations.
  • Fixed bug with mixin constructors.
  • Internal use of "_invariant" changed to "__invariant" to avoid conflicts with user code.
  • Fixed dmd hang on transcoding some utf strings.
  • Interfaces used as an argument to synchronized statements are now automatically cast to Object.

What's New for D 0.104

Oct 21, 2004

Bugs Fixed

  • Fixed linker bug with unknown CV version.

What's New for D 0.103

Oct 20, 2004

New/Changed Features

  • Improved symbolic debug info generation for Win32.
  • Added Dwarf2 line number debug info for linux.
  • Added Dave Fladebo's speedups to associative arrays.

Bugs Fixed

  • Removed redundant declaration of MAP_FAILED from Phobos.
  • Fixed codegen scheduling bug.
  • Incorporated Dave Fladebo's linux phobos makefile improvements.
  • Incorporated David Friedman's std.thread pause fix.

What's New for D 0.102

Sep 20, 2004

New/Changed Features

  • Upgraded etc.c.zlib to 1.2.1 (thanks to Sean Kelly).
  • Improved performance of array append (thanks to Dave Fladebo).
  • Added \dmd\bin\make.exe.
  • Improved Phobos makefiles.

Bugs Fixed

  • Fixed private module construction order.
  • Folded in Dave Fladebo's fix to std.zlib.
  • Fixed array append seg fault under linux.
  • Fixed problem where COMDATs could not exist in multiple modules.
  • Fixed seg fault on const fields as lvalues.
  • Fixed Internal error: ../ztc/cod1.c 2498
  • Fixed Internal error: e2ir.c 447
  • Fixed seg fault with empty debug statement.
  • Fixed seg fault with undefined qualified types.
  • Fixed error recovery with void in arithmetic expressions.
  • Fixed assertion failure 1147 in expression.c.
  • Fixed Internal error: ../ztc/cod2.c 4207
  • Eliminated trailing 0 in returned array from std.file.getcwd()
  • Fixed "cd" command in make.exe.

What's New for D 0.101

Aug 30, 2004

New/Changed Features

  • Added Ben Hinkle's improvements to std.stream. Ben writes: "I've attached a modified version of std.stream and phobos.html that include the bug fixes and behavior changes outlined in the newsgroup post yesterday. The bug fixes are almost entirely backwards compatible. The biggest difference is the change that opening a file on Windows with FileMode.In errors when the file doesn't exist. That makes it the same behavior as Linux and it just seems to make sense. I also did things like added writef and changed the Error classes to Exception."
  • Kris pointed out that version identifiers have global effect, and are dependent on which order modules are imported. This is clearly wrong. Now, only version and debug definitions on the command line have global effect. Others only influence the module they are declared in. Furthermore, version and debug definitions can only be done at module scope.

Bugs Fixed

  • Fixed "super" bug introduced by 0.99.
  • Missing function body after 'in' now diagnosed.
  • Function literals can now have same type signature.
  • Fixed problem with 'out' parameters in nested functions.
  • Fixed array initialization causing seg fault.
  • Fixed compiler gpf on invalid enum syntax.
  • Fixed Internal error: ..\ztc\cod1.c 3251
  • Fixed FPU stack overflow bug.
  • Fixed float optimization bug.
  • Fixed bug in conversion of string literals to UTF-16.

What's New for D 0.100

Aug 20, 2004

Bugs Fixed

  • Fixed Internal error: ..\ztc\cgcs.c 213 introduced by 0.99.
  • Hopefully fixed linux seg fault ENTER problem.

What's New for D 0.99

Aug 19, 2004

New/Changed Features

  • Added std.string functions ifind() and irfind() (thanks to David L. Davis).
  • Slicing of bit arrays now allowed if lower bound lands on a byte boundary.
  • Bit pointer offsets now are in number of bits, however, they must be a multiple of 8.
  • Improved performance of stack array initialization.
  • Idiom of using std.c.stdlib.alloca() with a constant value now recognized.
  • Removed implicit cast to void. What was I thinking?
  • Moved setErrno() from std.c.linux.linux to std.c.stdlib.
  • Added setErrno() to std.c.stdlib.
  • Improved code gen on cast of 'this' to interface.
  • Added implicit declaration of length to index and slice expressions. This will break existing code if length is used as a variable within [ ].

Bugs Fixed

  • Some overloading errors fixed.
  • ~ now works on bit operands.
  • Copy of non-byte aligned upper bound of bit array copies no longer copies too many bits.
  • Fixed cast of bit to byte.
  • Fixed MI bug with interface vtbl dispatch.
  • Fixed Internal error: ..\ztc\el.c 723
  • Fixed gpf on forward reference of mixin.
  • Fixed Internal error: ..\ztc\dt.c 104
  • Fixed Internal error: ..\ztc\cgcod.c 552
  • Fixed error recovery on bad initializers.
  • Diagnoses error on arithmetic on class references.
  • Fixed Internal error: ..\ztc\cgcod.c 1464
  • Fixed internal error: ..\ztc\cgcs.c 353
  • Fixed unresolved external when expanding nested templates in imports.
  • Fixed mysterious TOK881 message.
  • Fixed compiler gpf with using const char[] as enum value.
  • Fixed compiler gpf with error recovery.

What's New for D 0.98

Aug 5, 2004

New/Changed Features

  • One can now 'new' a scalar type, for example:
    int* p = new int;

Bugs Fixed

  • Fixed bug where typedef/alias members of a class weren't found when looked up via an instance of that class.
  • Added Berin Loritsch's fixes to pi.d.
  • Better detection of recursive template instantiation errors.
  • Improved error message for implicit conversion errors.
  • Fixed gpf on erroneous template instantiations.
  • Fixed name mangling of D __import__ symbols from DLLs.
  • Fixed Assertion failure: 267 'declaration.c'
  • Fixed Internal error: ..\ztc\cgcod.c 1464
  • Fixed Assertion failure: 1204 'expression.c'
  • Fixed some error recovery for undefined identifiers.
  • Fixed Internal error: ..\ztc\cgcs.c 350
  • Fixed Internal error: ..\ztc\cod1.c 2244
  • Access checking now done after overload resolution rather than before.
  • Fixed gpf on static initializers for function local structs.
  • Fixed error recovery on undefined identifiers.
  • Fixed gpf on const arrays without initializers.
  • Fixed Assertion failure: 3154 'mtype.c'
  • Fixed Assertion failure: 1203 'func.c'
  • Fixed Internal error: ..\ztc\cg87.c 1968

What's New for D 0.97

Jul 26, 2004

New/Changed Features

  • Added missing overload (opPos) for unary plus.
  • B.O.M. no longer required for UTF-16 and UTF-32 source text (thanks to Arcane Jill).

Bugs Fixed

  • Fixed linux bug where sometimes global symbols were not made public in .o file.
  • Fixed linux bug with function returns of small structs from C functions.
  • Implemented listdir() for linux (thanks to Christopher E. Miller and Andre Fornacon)
  • Deprecated functions can now call other deprecated functions without causing an error.
  • Check for deprecated functions now done after overloading rather than before.
  • Fixed some forward reference problems with interfaces.
  • Fixed compiler GPF with va_arg.
  • Fixes for std.system (thanks to Thomas Kuehne)
  • Fixed method alias ordering conflict in derived class.
  • Fixed std.utf bugs (thanks to Stewart Gordon)

What's New for D 0.96

Jul 21, 2004

New/Changed Features

  • Added exec* functions to std.process. (thanks to Matthew Wilson)
  • Added std.perf (thanks to Matthew Wilson)

Bugs Fixed

  • Fixed compiler crash on circular class derivations.
  • Invalid UTF characters in string literals now diagnosed.
  • Date parsing can now handle time zone offsets that are not in hourly increments.
  • Fixed incorrect handling of precision for strings in std.format.
  • Fixed auto bug inside template bodies.
  • Fixed static initializations of the form int[2]x=3;
  • Added some missing line numbers in error messages.
  • Fixed an alias resolution problem.
  • Break/continue in try and syncrhonized blocks now matches documentation.
  • Function out parameters are now initialized at the start of the function.
  • Fixed mishandling of out parameters in variadic functions.
  • Fixed problem of undefined symbols at link time when templates are expanded in interface declarations.
  • Template default arguments for parameters now are 'lazily' semantically analyzed, which means they can refer to previous template argument types.
  • Fixed DMD GPF when trying to index a mixin with [].
  • time_t definition removed from std.c.linux.linux, as it conflicted with definition in std.c.time.

What's New for D 0.95

Jul 6, 2004

New/Changed Features

  • Added printf replacement, std.stdio.writef and related functions.
  • Added std.format for formatting strings.
  • Rewrote std.string.format() for full functionality.

Bugs Fixed

  • Fixed Internal error: ..\ztc\cgcod.c 614
  • Fixed overflow detection on static array dimension.
  • Fixed Internal error: ..\ztc\cod4.c 352
  • Now detects attempts to use non-identifer character filenames as module names.
  • Can now overload static member functions with non-static ones within a static one.
  • Now detects attempts to overload destructors.
  • Fixed compiler exit status under linux (thanks to Sam McCall).
  • Fixed poor error recover from undefined template identifier.
  • Better forward reference handling.
  • Fixed problems with local statics having name collisions.

What's New for D 0.94

Jun 27, 2004

Bugs Fixed

  • Missing TypeInfo for bit added.
  • Incorrect integral type promotion for variadic arguments fixed.
  • Fixed std.string.toStringz() 0 termination bug.
  • Fixed some .size => .sizeof deprecations in library.
  • Fixed std.stream.File.open() and std.stream.File.create() to handle UTF filenames (thanks to Carlos Santander Bernal).
  • Fixed std.uri.encode() bug with Octets.
  • Fixed codegen error with typedef'd static arrays.
  • Correct error message now generated when using an array initializer as an expression.
  • Fixed "frame" error when compiling.
  • Fixed compiler GPF on getting boolean value of module name.
  • Fixed compiler GPF with function with all default arguments.
  • Fixed bug with associative array typedef'd indices.
  • Fixed TypeInfo crash with arrays of null Objects.
  • Fixed Internal error: ..\ztc\blockopt.c 1941
  • Fixed Internal error: ..\ztc\cod1.c 2244
  • Fixed Assertion failure: '0' on line 80 in file 'mtype.c'

What's New for D 0.93

Jun 22, 2004

New/Changed Features

  • char.init is now 0xFF, wchar.init is 0xFFFF, dchar.init is 0x0000FFFF. Thanks to Arcane Jill.
  • Array operator assignment overloading with opIndex(index, value) is now deprecated. Use opIndexAssign(value, index) instead.
  • Multiple indices are now allowed with array operator overloading.
  • Added _arguments[] and _argptr to variadic functions.
  • Added TypeidExpressions.
  • .typeinfo property is now deprecated (use TypeidExpression instead).
  • Replaced std.c.stdarg with std.stdarg.

Bugs Fixed

  • Some minor error message improvements.
  • Fixed bug where local class static constructor did not get called.
  • Fixed Assertion failure: 'f' on line 2695 in file 'expression.c'
  • Fixed Internal error: ..\ztc\cgcs.c 353
  • Fixed dmd GPF when module used as array.

What's New for D 0.92

Jun 7, 2004

New/Changed Features

  • Modified Object.toString() and Object.print() to print out the name of the object instance's class.
  • The Expression within an array's brackets is now an AssignExpression (meaning that commas are no longer allowed).
  • Added default arguments to function parameters. Semantics are like C++.
  • Added package attribute for package level access.
  • Added operator overloads opAdd_r, opMul_r, opAnd_r, opOr_r, and opXor_r.
  • Modified operator overloading rules so functionality can be added to the lvalue of an operator overload for user defined rvalues without needing to modify the lvalue's class.

Bugs Fixed

  • Fixed parsing bug in typeof(this).func();
  • Fixed nested multiple inheritance bug with interfaces.
  • Fixed compare() bug in typeinfo's for int and uint. Thanks to Stewart Gordon.

What's New for D 0.91

May 27, 2004

New/Changed Features

  • Allow functions that return void to return expressions.
  • Added support for typeof(this) and typeof(super). outside of non-static member functions.
  • Added cast operator overloading.
  • typeof(this).member() now does non-virtual call to member().
  • Mixin qualifier names now work for class members.

Bugs Fixed

  • Fixed std.file.listdir unicode issue with Win95.
  • Fixed incorrect diamond inheritance of interface classes.
  • std.string.capwords() now converts non-first characters of a word to lower case.
  • Fixed problem with super in mixins.
  • Fixed assert failure mtype.c 2575
  • Fixed bad formatting of typedef* error messages.
  • Fixed std.string.toString(char).
  • Fixed bug accessing private static from inlined function.
  • Fixed compiler gpf on synchronized blank for statement inits.

What's New for D 0.90

May 20, 2004

Bugs Fixed

  • Fixed problem with mixins overriding same function more than once.
  • Added ability for invariants and other special functions to be in mixins.
  • Fixed error diagnostic for delegate literals in class declarations.
  • Fixed extended comparison operators so they work on integral types when constant folding.
  • Fixed bug with mixin functions for interfaces.
  • Fixed Internal error: ..\ztc\cod1.c 1641
  • Fixed name lookups for special functions in mixins.

What's New for D 0.89

May 17, 2004

New/Changed Features

  • Allow void() to be omitted from function literals.
  • Mixins added.
  • A WithStatement now works on struct instances.

Bugs Fixed

  • Added Stewart Gordon's windows.d function pointer fixes.
  • Added Stewart Gordon's std.asserterror fixes.
  • Added Ben Hinkle's std.stream fixes.
  • Fixed bug with template function alias arguments.

What's New for D 0.88

May 5, 2004

New/Changed Features

  • Added std.c.stdarg (thanks to Hauke Duden).
  • C style casts deprecated (use -d to compile them for now).
  • instance style template instantiation deprecated (use -d to compile them for now).

Bugs Fixed

  • Fixed problem with template classes and opCall.
  • Fixed problems with implicit this and member template functions.
  • Fixed problem with property in [] of NewExp.
  • Now correctly diagnoses problem with using local as template parameter alias.
  • Fixed bug with no identifier for declarator in template type.
  • Fixed const folding with ?: operator.
  • Fixed std.utf.toUTF32() with J C Calvarese's fix.
  • Included David Friedman's fixes for linux monitors.
  • Fixed bug with overloading alias template parameters.
  • Fixed internal error cg87 1235.
  • Superclass dtors now called for class deallocator.
  • Fixed _d_delmemory() taking the wrong argument.
  • Fixed auto super dtors.
  • Fixed multi argument struct new's with custom new.
  • Fixed custom deallocator struct delete.
  • Monitors now deleted when object is deleted.

What's New for D 0.86

Apr 23, 2004

New/Changed Features

  • Added template default parameters.
  • Added casting ability to non-COM interfaces.
  • Added Christopher E. Miller's std.socket and std.socketstream.
  • Added std.mmfile (thanks to Matthew Wilson!)

Bugs Fixed

  • An error is now issued when the argument to delete is a COM interface object.
  • Incorporated Antonio Monteiro's fixes for std.date and std.zip.
  • Error now diagnosed when EnumBaseType is not integral.
  • Fixed delete on non-class objects.

What's New for D 0.82

Mar 28, 2004

Bugs Fixed

  • Some cases of forward referenced classes are now handled.
  • Illegal recursive alias declarations now correctly diagnosed.
  • Erroneous anonymous struct member offsets within unions fixed.
  • Fixed problem with array initializers for consts.
  • Fixed bug with intrinsics.
  • Can now slice a void[].
  • std.date: fixed dst calculation for zones with no dst.
  • Fixed bug with nested delegate literals.
  • Fixed overload inheritance bug with function aliases from base classes.
  • Added files gnuc.h, mem.h, mem.c, port.h, enum.h, and enum.c to the \dmd\src\dmd.
  • Fixed seg fault on forward reference to template.
  • Fixed std.date.getUTCtime() for linux.

What's New for D 0.81

Mar 7, 2004

Bugs Fixed

  • Fixed problem with class and modules having the same name.
  • Fixed access problem with protected members of base class.

What's New for D 0.80

Mar 5, 2004

New/Changed Features

  • Added overloads for basic types for std.string.toString().
  • Modified front end source to be more compatible with GDMD project.
  • Implicit conversions of floating point values to integer values is now disallowed.

Bugs Fixed

  • Fixed dmd crash with module and class name conflict.
  • Fixed bug where f(x)(y); was interpreted as declaring x as a function taking parameter type y and returning type f, instead of f being an instance of a class with () overloaded. There's still the problem of f(*p)(y), though, the solution is to probably just deprecate the C function pointer declaration syntax.
  • Fixed using super in nested function.
  • Function members without bodies in non-abstract classes now reference an external symbol rather than inserting a 0 in the vtbl[].
  • Fixed Internal error: ../ztc/cgcod.c 1459
  • Fixed problems with template aliases.
  • Improved semantic analysis with member templates.
  • Adding some missing file/line numbers to error messages.
  • Fixed bug with property syntax in return expression.
  • Fixed problem with template expansion contexts.

What's New for D 0.79

Feb 2, 2004

New/Changed Features

  • Added utf decoding capability to foreach statement.
  • Added Christopher Miller's std.base64.
  • Fixed gc per D/21217

Bugs Fixed

  • Fixed std.file failure on Win95 (hopefully got it right this time!).
  • Fixed code gen error with unsigned % 10.
  • Fixed problem with std.regexp.test and multiple calls.
  • Fixed Internal error: ..\ztc\cgcod.c 2241
  • Fixed chained assignments to bit arrays.
  • Fixed bugs with foreach over a bit array.
  • Fixed many problems with recursive templates.
  • Fixed Assertion failure on line 67 in file 'template.c'
  • Fixed problem with optimization of short registers.

What's New for D 0.78

Jan 14, 2004

New/Changed Features

  • std.string.find() and .rfind() upgraded to support dchar searches within char[] strings.
  • Fixed std.ctype functions to accept/return dchar types instead of char types.
  • // comments can now be terminated by end of file rather than a newline.

Bugs Fixed

  • Fixed Internal error e2ir.c 133
  • Fixed Internal error: ..\ztc\cod1.c 2240
  • Fixed Internal error: ..\ztc\cod2.c 4116
  • Fixed crash on invalid template syntax.
  • std.file functions now fall back to "A" functions on Win9x systems.
  • Fixed problem with static arrays of structs with non-zero default initializations.
  • Fixed crasher with structs declared but not defined.
  • Fixed critical section bug in Win95.

What's New for D 0.77

Jan 2, 2004

New/Changed Features

  • Changed std.file so unicode filenames work.
  • Added toUTF16z to std.utf.
  • Added std.md5.
  • Hex strings must now contain an even number of hex digits.
  • Added .alignof property.
  • Added .sizeof property which has same value as .size, but won't conflict with C/C++ struct member names.
  • Global main must be main() or main(char[][] args).
  • Added size_t, ptrdiff_t predefined aliases. Use size_t as an alias for an unsigned integral type spanning the address space, and ptrdiff_t as an alias for a signed integral type spanning the address space. This will make the code portable from 32 to 64 bits.
  • .length, .size, .sizeof, and .alignof now return a value of type size_t.
  • For win32, converts '/' in source file names passed to dmd to '\' so that back end routines work consistently.
  • Added typeof.
  • Added pragmas.
  • Added expression lists to case statements.
  • Added goto default; and goto case; and goto case Expression; for use in switch statements.
  • Added template alias parameters.
  • Added new template instance syntax.
  • Added class template syntax.
  • Added template member injection rule.
  • Added Matthew Wilson's std.recls - for recursive file-system searching.

Bugs Fixed

  • Better error recovery in parser.
  • Sizes of bit arrays fixed.
  • Fixed conflict between std.intrinsic and std.math.
  • Fixed reset problem with std.regexp.match().
  • Fixed std.string.rfind().
  • Fixed several problems with -inline.

What's New for D 0.76

Nov 21, 2003

New/Changed Features

  • std.assert changed to std.asserterror.
  • Added keyword is, which has same function as ===.
  • Renamed operator overloading names.
  • Renamed std.assert to std.asserterror.
  • Added system to std.process.
  • Changes to std.file:
    • Added several functions to std.file.
    • Changed byte[] types for data in std.file to void[].
    • std.file.getSize() now returns a ulong.

Bugs Fixed

  • Library modules are all correctly named.
  • Library modules now have private imports.

What's New for D 0.75

Nov 4, 2003

New/Changed Features

  • Changed to new standard library package layout.
  • Changed apply to opApply.
  • Fixed foreach so it can have multiple parameters.
  • Added etc.c.zlib, a D interface to the C zlib compression library.
  • Added std.zlib, a compression module.
  • Added std.zip, a zip archive module.

What's New for D 0.74

Oct 15, 2003

New/Changed Features

  • Added support for Unicode characters in identifiers.
  • Version declarations can now wrap attribute : and they'll stick.
  • -of filename switch now accepts any extension.
  • Added D.win32.registry.

Bugs Fixed

  • Problems fixed with with abstract member function definitions.
  • Fixed problems with getting the wrong .classinfo with inherited classes.
  • Fixed internal error cgcod.c 1459
  • Fixed internal error e2ir.c 721
  • Fixed ICE for empty foreach bodies.
  • Fixed name mangling for out/inout parameters to extern (Windows) functions.
  • Fixed bug in ?: of string literals.
  • Fixed order-of-evaluation bug with &((new foo()).bar)
  • Can now assign null to delegates.
  • Fixed problem diagnosing error of slices as out parameters.
  • Fixed problem diagnosing error of const field initializations.
  • Fixed gc and multithread deadlock (thanks to jhenzie).

What's New for D 0.73

Sep 18, 2003

New/Changed Features

  • Added static asserts.
  • Added bswap as a compiler intrinsic function.
  • Added operator overloading for array index [], array slice [..] and function call () operators.
  • Added properties.
  • To take the address of a function, the & operator is required now, rather than being implicit.

Bugs Fixed

  • Implicit conversions of B[] to A[] are no longer allowed if B is derived from A. Gaping type safety holes are the reason.

What's New for D 0.72

Sep 14, 2003

New/Changed Features

  • Implicit conversions of B[] to A[] are now allowed if B is derived from A.
  • Functions in abstract classes can now have function bodies.

Bugs Fixed

  • Fixed bug with in and out instructions in inline assembler.
  • Fixed speed problem with %.*s printf format.
  • Fixed problem with foreach over array of arrays or structs.
  • Fixed compiler error with array rehash.
  • Now correctly issues error on self-initializations like:
    int a = a;
  • Fixed problem converting "string" to char[], it should be an exact conversion, not an implicit conversion.
  • Occaisional segfault during gc collection fixed.
  • Empty static arrays now placed in BSS segment.
  • Conversion of uint to real now works.

What's New for D 0.71

Sep 3, 2003

New/Changed Features

  • Added foreach statement.

Bugs Fixed

  • Fixed bug with nested functions.
  • Fixed bug with linux file.write() and file.append() functions.
  • Fixed bug with linux processing of /etc/dmd.conf.

What's New for D 0.70

Aug 24, 2003

New/Changed Features

  • Added wprintf() to object.d.
  • Extended alias to work for overloaded functions from another scope.

Bugs Fixed

  • Fixed incorrect handling of leading UTF-8 BOM mark.
  • Fixed 2 compiler GPF's.
  • Fixed problem with downcasting to interfaces.
  • Fixed linux seg fault with %@P% in DFLAGS.
  • Fixed inoperative -L switch for linux.

What's New for D 0.69

Aug 11, 2003

New/Changed Features

  • Added dchar keyword for UTF-32 characters.
  • ' ' strings are now character literals, not strings.
  • wysiwyg strings are not r"string", not 'string'.
  • `string` (backquotes) are also wysiwyg strings.
  • Added x"0a AA BF" style hex strings.
  • Implicit conversion of single character strings to character literals no longer happens.
  • Implicit conversions of string literals between UTF-8, UTF-16 and UTF-32 now happens.
  • Deleted command line switch -o, replaced it with -od, -of and -op. This should remove confusion and add flexibility.
  • Added bool as an alias for bit.
  • Integer and floating point literals can now have embedded _ for formatting purposes.

Bugs Fixed

  • Bit variables can now be out or inout function parameters.
  • Package names now part of mangled names.
  • Mangled names are now reversible unambiguously.
  • Fixed problem returning 8 byte structs from functions.
  • Fixed bug with typedef'd associative arrays.
  • Fixed bug with typedef'd return values.
  • Fixed error recovery from 'typedef struct'.
  • Fixed problems with Linux exception handling.
  • 0b... numeric literals now work under Linux.

What's New for D 0.68

Jul 8, 2003

New/Changed Features

  • Added TypeInfo's for classes and other basic types.
  • new'ing arrays of types with non-zero initializers now works.
  • new'ing bit arrays now works.
  • new'ing structs now works.
  • Fixed bug with typedef'd associative array index.
  • Falling off the end of a function that has a non-void return type now generates a runtime exception if a syntax error is not already generated.
  • Fixed parse bug with inout keyword in nested functions.
  • Fixed cgcs 350 error.
  • Fixed error where const objects could be assigned to.
  • Fixed crash with non-existent struct member names in initializers.
  • Fixed crash with const objects with no initializers.
  • Fixed cgobj 3115 error.
  • Correctly errors out now when slicing voids.

What's New for D 0.67

Jun 17, 2003

Bugs Fixed

  • Fixed some bugs.

What's New for D 0.66

Jun 8, 2003

New/Changed Features

  • Added uri module.
  • Added utf module.
  • Added constant folding for ?: operator.
  • Zero initialized structs no longer need to link to the module the struct was defined in.
  • Private imports now supported.
  • Class names common to multiple modules no longer collide, but this required a change to how class names are mangled. Hence, existing libraries will need to be recompiled.
  • templates of the form:
        template foo(T:T[])
    now correctly resolve T in foo(int[]) to int rather than int[].

What's New for D 0.65

May 13, 2003

Bugs Fixed

  • Another bad section name bug is hopefully fixed.

What's New for D 0.64

May 12, 2003

New/Changed Features

  • dmd.conf now needs to be installed as /etc/dmd.conf.
  • phobos.a has been renamed as libphobos.a and been placed in the /usr/lib directory.
  • dmd will now do the link step automatically.
  • The bad section name bug is hopefully fixed.

What's New for D 0.63

May 10, 2003

New/Changed Features

  • Added linux version. Thanks to Burton Radons and Pat Nelson for the help.

What's New for D 0.61

Mar 30, 2003

New/Changed Features

  • Incorporated Burton Radon's stream.d fixes.
  • Improved performance of string switches and string concatenation.
  • Phobos library is now built optimized.
  • Fixed numerous reported bugs.

What's New for D 0.59

Mar 6, 2003

New/Changed Features

  • Fixed bugs in nested functions.
  • Refactored code so it compiles with gnuc.

What's New for D 0.58

Mar 3, 2003

New/Changed Features

  • Added covariant function return types.
  • Fixed several bugs in nested functions, template argument deduction, access protections, constant folding, etc.

What's New for D 0.57

Feb 25, 2003

New/Changed Features

  • Added keyword function and new function pointer syntax analogous to the way the delegate declaration syntax works.
  • Added function literals.
  • Added nested functions.
  • Added closures.
  • Fixed struct/class definitions nested within functions.
Many thanks to Burton Radons for his help with this.

What's New for D 0.56

Feb 20, 2003

New/Changed Features

  • Fixed a couple bad bugs with template typedefs and arrays.

What's New for D 0.55

Feb 17, 2003

New/Changed Features

  • Added several new math functions to math.d.
  • Changed behavior of new expressions to match change in array declaration order:
        char[][] foo;
    foo = new char[][45];	// new, correct way to allocate array of 45 strings
    //foo = new char[45][];	// old, now wrong, way
  • Fixed some problems with error recovery.
  • The module name is now in its own scope enclosing the scope of the contents of the module (before it was simply inaccessible).

What's New for D 0.54

Feb 14, 2003

New/Changed Features

  • Fixed some parsing problems with template instances.
  • Introduced new types cfloat, cdouble, ifloat, idouble.
  • Introduced new constant types ifloat, idouble.
  • Renamed extended to real.
  • Renamed imaginary to ireal.
  • Renamed complex to creal.
  • Reversed order of array declarations when they appear to the left of the identifier being declared. Postfix array declaration syntax remains the same (and equivalent to C).
        int[3][4] a;	// a is 4 arrays of 3 arrays of ints
    int b[4][3];	// b is 4 arrays of 3 arrays of ints
These changes have been needed for a while

What's New for D 0.53

Feb 8, 2003

New/Changed Features

  • Added ability for explicit memory allocation/deallocation.

What's New for D 0.52

Feb 5, 2003

New/Changed Features

  • The argument to a with statement can now be a template instance.
  • The inline asm for FCOMI/FCOMIP/FUCOMI/FUCOMIP can now accept the ST,ST(i) form of the instruction to match the Intel documentation.
  • Fixed numerous minor bugs.

What's New for D 0.51

Jan 27, 2003

New/Changed Features

  • Added template value parameters (as opposed to just type parameters).
  • Fixed several problems with templates.
  • Added #line pragma support.
  • D can now accept source files in various UTF formats.

What's New for D 0.50

Nov 20, 2002

New/Changed Features

  • To convert to type bit now requires an explicit cast, rather than implicit. The conversion (cast(bit)i) is now performed as (i?true:false).
  • Added library functions string.toString().
  • Fixed many template bugs.
  • Changed implicit conversion rules for integral types; implicit conversions are not allowed if the value would change. For example:
        byte  b = 0x10;		// ok
    ubyte c = 0x100;	// error
    byte  d = 0x80;		// error
    ubyte e = 0x80;		// ok

What's New for D 0.49

Nov 18, 2002

New/Changed Features

  • Added LINKCMD to sc.ini to specify which linker to use.
  • Multiple -I switches can now be used, and the paths are searched in order.
  • Fixed bug in regexp with blank substitutions.
  • Removed "reference to this before super()" error.
  • % and %= floating point operations are now handled by code generator instead of library.
  • Fixed GCStats linking problem.
  • Fixed many other minor problems.

What's New for D 0.48

Oct 25, 2002

New/Changed Features

  • Added conv to phobos library.
  • Fixed a number of bugs that were blocking people.

What's New for D 0.47

Oct 22, 2002

Bugs Fixed

  • Fix Burton's reported bugs on arrays of small structs, and unit test failures in stream.d.

What's New for D 0.46

Oct 22, 2002

New/Changed Features

  • Fixed problem with auto class constructors.
  • Fixed problem with calling class invariants with -O.
  • Redid lib.exe command syntax to simplify makefiles.
  • String literals can now span multiple lines.
  • Fixed bugs in handling access violations and other windows exceptions.
  • Revamped support for generating Windows GUI apps.
  • Fixed some code gen bugs.

What's New for D 0.45

Oct 8, 2002

New/Changed Features

  • Redid constructor semantics to improve reliability.
  • Expanded inlining capability.
  • Redid interface semantics.
  • Fixed problems with ~ string concatenation.

What's New for D 0.44

Oct 1, 2002

New/Changed Features

  • Clarified interface semantics and fixed problems with it per Joe Battelle's suggestions.

What's New for D 0.43

Sep 28, 2002

New/Changed Features

  • Added new VolatileStatement.
  • Added auto storage class and auto classes to implement RAII. See here and here.

What's New for D 0.42

Sep 12, 2002

New/Changed Features

  • Implemented new alias declarations.

What's New for D 0.41

Sep 9, 2002

New/Changed Features

  • Implemented new array resizing algorithms.

What's New for D 0.40

Sep 8, 2002

New/Changed Features

  • Implemented templates.

What's New for D 0.39

Aug 28, 2002

New/Changed Features

  • Just some nuisance bugs fixed.

What's New for D 0.38

Aug 21, 2002

New/Changed Features

  • Fleshed out operator overloading support.

What's New for D 0.37

Aug 18, 2002

New/Changed Features

  • www.digitalmars.com/d/operatoroverloading.html It doesn't do all the operators yet, but it's a start.

What's New for D 0.36

Aug 15, 2002

Bugs Fixed

  • A long, but unspecified, list of bug fixes.

What's New for D 0.35

Jun 3, 2002

New/Changed Features

  • Add support for sc.ini file

What's New for D 0.34

May 31, 2002

New/Changed Features

  • Made public/protected/private work

Bugs Fixed

  • Fixed some bugs

What's New for D 0.32

May 17, 2002

New/Changed Features

  • Now will inline functions with the -inline switch.
  • DMD will now do the link for you, no need to use SC.

Bugs Fixed

  • Fixes numerous problems with bit arrays and arrays in general.

What's New for D 0.30

Apr 27, 2002

Bugs Fixed

  • Fixed several reported bugs

What's New for D 0.29

Apr 23, 2002

New/Changed Features

  • Released the front end compiler source

What's New for D 0.28

Apr 21, 2002

New/Changed Features

  • Implements the new ==, !=, comparison, === and !== semantics

What's New for D 0.27

Apr 16, 2002

New/Changed Features

  • Add a threading library and make the GC thread aware www.digitalmars.com/d/phobos.html#thread

What's New for D 0.26

Apr 10, 2002

New/Changed Features

  • implement delegates: described in www.digitalmars.com/d/type.html
  • works under Win98 now.

What's New for D 0.25

Apr 7, 2002

New/Changed Features

  • Lots of internal work reorganizing the compiler to be more consistent.
  • Better error messages.
  • Implemented .init properties.
  • Added time and date functions.
  • Includes Pavel's math2 package.
  • Some of the front end code in \dmd\src\dmd\

What's New for D 0.24

Mar 29, 2002

New/Changed Features

  • Release source to lexer and parser
  • Added array.reverse, .sort, etc

Bugs Fixed

  • Fixed a raft of array handling bugs

What's New for D 0.23

Mar 26, 2002

New/Changed Features

  • Mostly under the hood rewrites of associative arrays.

Bugs Fixed

  • Fixed some problems Pavel found.

What's New for D 0.22

Mar 14, 2002

New/Changed Features

  • This has the garbage collector rewritten in D.
  • The C++ code has been replaced with D code in the Phobos source code. The gc is a little slower at the moment because I haven't implemented inline functions yet. Inline functions will close the performance gap between C and D, though D has the potential for better optimization than C.
  • Intrinsic functions like I/O port calls added: www.digitalmars.com/d/phobos.html#intrinsic

What's New for D 0.20

Feb 26, 2002

New/Changed Features

  • Added inline assembler

What's New for D 0.19

Feb 8, 2002

Bugs Fixed

  • win98 crash
  • /+ +/ commenting
  • function pointer types
  • etc

What's New for D 0.16

Jan 20, 2002

New/Changed Features

  • Array bounds checking

What's New for D 0.15

Jan 15, 2002

New/Changed Features

  • I've finally got packages implemented www.digitalmars.com/d/module.html
  • Note that stdio is now c.stdio, and stdlib is now c.stdlib.

What's New for D 0.11

Jan 4, 2002

Bugs Fixed

  • No changelog

What's New for D 0.10

Jan 2, 2002

Bugs Fixed

  • No changelog

What's New for D 0.07

Dec 28, 2001

Bugs Fixed

  • No changelog

What's New for D 0.04

Dec 23, 2001

Bugs Fixed

  • Fixes long list of bugs submitted by people

What's New for D 0.03

Dec 19, 2001

Bugs Fixed

  • Fixed a lot of bugs regarding arrays and strings. Check out strings.d, the D string runtime library functions. It makes much use of array slicing and unit tests.

What's New for D 0.02

Dec 16, 2001

Bugs Fixed

  • interface calls, casts, implicit conversions, vtbl[]'s
  • import object; is now implicitly done
  • Object is now the default base class
  • overloading at module level now works

What's New for D 0.01

Dec 9, 2001

Bugs Fixed

  • Fixed reported bugs

What's New for D 0.00

Dec 8, 2001

New/Changed Features

  • Initial release


Change Log

Last update Sun Dec 30 20:34:43 2012

D Change Log

  • What's new for D 1.00
  • What's new for D 0.178
  • What's new for D 0.177
  • What's new for D 0.176
  • What's new for D 0.175
  • What's new for D 0.174
  • What's new for D 0.173
  • What's new for D 0.172
  • What's new for D 0.171
  • What's new for D 0.170
  • What's new for D 0.169
  • What's new for D 0.168
  • What's new for D 0.167
  • What's new for D 0.166
  • What's new for D 0.165
  • What's new for D 0.164
  • What's new for D 0.163
  • What's new for D 0.162
  • What's new for D 0.161
  • What's new for D 0.160
  • What's new for D 0.159
  • What's new for D 0.158
  • What's new for D 0.157
  • What's new for D 0.156
  • What's new for D 0.155
  • What's new for D 0.154
  • What's new for D 0.153
  • What's new for D 0.152
  • What's new for D 0.151
  • What's new for D 0.150
  • What's new for D 0.149
  • What's new for D 0.148
  • What's new for D 0.147
  • What's new for D 0.146
  • What's new for D 0.145
  • What's new for D 0.144
  • What's new for D 0.143
  • What's new for D 0.142
  • What's new for D 0.141
  • What's new for D 0.140
  • older versions
  • Download D compiler for Win32 and x86 linux
  • tech support
Version D 1.00 Jan 2, 2007

New/Changed Features

  • -v flag now outputs imports
  • added std.c.linux.pthread

Bugs Fixed

  • Fixed Bugzilla 552: Internal error: ..\ztc\cg87.c 1327 on in-function modulo of imaginary number
  • Fixed Bugzilla 553: Assertion failure: '0' on line 609 in file 'constfold.c' on modulo of complex number
  • Fixed Bugzilla 694: Doc mistake: a == null is not a.opCmp(null)
  • Fixed Bugzilla 699: long variadic arguments and the "-profile" flag
  • Fixed Bugzilla 702: inline assembler: "SMSW r32" fails to compile
  • Fixed Bugzilla 703: SuperExp::scanForNestedRef Assertion
  • Fixed Bugzilla 728: incorrect initialisation of member arrays if an explicit struct initializer is used
  • Fixed Bugzilla 731: Positive and negative NaN in template arguments causes link conflict
  • Fixed Bugzilla 734: Multidimensional arrays use incorrect initializer
  • Fixed Bugzilla 745: recursive typeof in function declaration crashes cc1d
  • Fixed Bugzilla 748: internal error with mixed static / dynamic array
  • Fixed Bugzilla 749: Internal error: toir.c 170 with lazy bool and delegate with default argument
  • Fixed Bugzilla 750: Recursive typeof in function declaration crashes DMD
  • Fixed Bugzilla 751: Compiler segfault on template expansion
  • Fixed Bugzilla 752: Assertion failure: 'e->type->ty != Ttuple' on line 4518 in file 'mtype.c'
  • Fixed Bugzilla 753: Minor Misspelling in Class Spec Page
  • Fixed Bugzilla 754: hex strings crash DMD when reporting syntax errors
  • Fixed Bugzilla 757: Some debug code was not removed from statement.c
  • Fixed Bugzilla 760: std.c.stdlib does not include system(3)
  • Fixed Bugzilla 763: Segfault compiling template code on Linux
  • Fixed Bugzilla 764: (typeof(o)).classinfo causes parser error
  • Fixed Bugzilla 765: ArrayBoundsError when assigning slice of pointer
  • Fixed Bugzilla 766: dmd.exe crash
  • Fixed Bugzilla 770: enums and typecasts
  • Fixed Bugzilla 771: template func returns delegate w. param list from tuple and type, odd compiler error
  • Fixed Bugzilla 772: Bogus error using relation operator as static if expression within template
  • Fixed Bugzilla 773: Redundant "Error: " in std.conv.ConvError
  • Fixed Bugzilla 775: array literals can't be used as template arguments
  • Fixed Bugzilla 777: -inline: assert() with a non-constant message causes code to not compile
  • Fixed Bugzilla 778: -inline: Assertion failure: '!v->csym' on line 450 in file 'glue.c'
  • Fixed Bugzilla 779: init.c:103: virtual Expression* VoidInitializer::toExpression(): Assertion `0' failed.
Version D 0.178 Dec 23, 2006

New/Changed Features

  • Implemented Named Return Value Optimization
  • If the first element of an array literal is a static array, it is converted to a dynamic array.
  • Empty ; no longer allowed after conditional statements, see Bugzilla 576.

Bugs Fixed

  • Fixed Bugzilla 39: ArrayMemberInitialization, StructMemberInitializer inconsistencies from dmd's behavior
  • Fixed Bugzilla 40: DecimalFloat spec doesn't match dmd behavior
  • Fixed Bugzilla 238: Cannot initialise const field from foreach loop on associative array
  • Fixed Bugzilla 265: Selective import from renamed import behaves strangely
  • Fixed Bugzilla 576: version.html - ConditionalStatement grammar doesn't make sense
  • Fixed Bugzilla 577: statement.html - NonEmptyStatement grammar lists DebugStatement and VersionStatement, which are not defined
  • Fixed Bugzilla 612: Associative arrays ignore opEquals, contrary to the spec
  • Fixed Bugzilla 630: Obscure, unimplemented features related to in/out contracts
  • Fixed Bugzilla 631: Spelling errors in DMD distribution
  • Fixed Bugzilla 634: writef doesn't work on enums
  • Fixed Bugzilla 635: regression: looping "Error: outer class Outer 'this' needed to 'new' nested class Inner"
  • Fixed Bugzilla 650: Assertion failure: '0' on line 774 in file 'expression.c'
  • Fixed Bugzilla 651: Assertion failure: 'global.errors' on line 2622 in file 'template.c'
  • Fixed Bugzilla 654: Const string member using implicit type inference gives garbage in certain situation
  • Fixed Bugzilla 661: Error using a zero-init struct's init property
  • Fixed Bugzilla 663: Slice assignment does not bounds check when it should
  • Fixed Bugzilla 665: missing functions in std.c.linux.linux
  • Fixed Bugzilla 667: incorrect value for std.socket.SocketShutdown.BOTH
  • Fixed Bugzilla 669: (a == b) misuses opCmp and opEquals
  • Fixed Bugzilla 672: Compiler endless loop with nested class object
  • Fixed Bugzilla 673: ABI as documented is 32 bit specific.. how about 64 bits?
  • Fixed Bugzilla 681: Array -- Implicit type doc updates needed
  • Fixed Bugzilla 682: dmd segfault with vararg template
  • Fixed Bugzilla 683: New: dmd segv, this ain't the same as bug 682
  • Fixed Bugzilla 684: dmd should compile this
  • Fixed Bugzilla 685: dmd assertion failure
  • Fixed Bugzilla 686: [Regression] opCast of a struct or union is called in nonsensical circumstances
  • Fixed Bugzilla 687: DDoc doesn't document anonymous enums
  • Fixed Bugzilla 688: Implicit function template match doesn't work for classes
  • Fixed D.announce/6072
  • Fixed D/45058 items 1, 2 and 4
  • Fixed D.bugs/6300: Assertion failure: '0' on line 704 in file 'expression.c'
  • Fixed c++/5355
Version D 0.177 Dec 9, 2006

New/Changed Features

  • Casting a value v to a struct S is now rewritten as S(v).
  • Initializing a struct S from a value v is now rewritten as S(v).
  • TypeInfo now always generated for enum, struct, and typedef's, to enable more thorough rtti.
  • classinfo.name now has the fully qualified name
  • Arrays no longer implicitly convert to pointers unless -d is used.
  • Need to recompile because:
    • Improved name mangling for floating point constants
    • Nested and member functions needing 'this' are preceded by 'M' in the mangled type.

Bugs Fixed

  • Doc fixed for Bugzilla 510: Nonworking implicit conversions between arrays and pointers
  • Doc fixed for Bugzilla 511: Various problems in the documentation
  • Doc fixed for Bugzilla 567: Compiler crash with conflicting templates
  • Fixed Bugzilla 607: toString can't handle char[]
  • Fixed Bugzilla 628: Assertion failure: '0' on line 91 in file 'init.c'
  • Fixed Bugzilla 636: Excessive "1: " in error message
  • Fixed Bugzilla 637: internal symbols are missing the leading underscore
  • Fixed Bugzilla 638: additional leading D in symbol D_D3std9dateparse9DateParse8classifyFAaZE3std9dateparse9DateParse2DP6DateID6__initZ
  • Fixed Bugzilla 653: AAs are slightly broken
  • Fixed Bugzilla 656: lazy in main
Version D 0.176 Dec 2, 2006

New/Changed Features

  • Added std.bind.
  • Need to recompile because:
    • Associative arrays now are PTRSIZE, not PTRSIZE*2.
    • Destructors no longer stored in vtbl[].
    • "_arguments" now passed differently to variadic functions.
    • Improved name mangling, see D.announce/5791 and D.announce/5759.

Bugs Fixed

  • Fixed Bugzilla 221: Inconsistent name mangling of bool (a relic of 'bit') [Patch included]
  • Fixed Bugzilla 294: DDoc: Function templates get double and incomplete documentation
  • Fixed Bugzilla 500: Struct Initializers conflict with Delegate Literals in initializers
  • Fixed Bugzilla 501: Bad interaction between 'with' and IFTI in template methods
  • Fixed Bugzilla 503: Names of arguments to atan2 are backwards
  • Fixed Bugzilla 505: rdmd and dmd do not correctly preserve program arguments with spaces.
  • Fixed Bugzilla 507: Error: 'this' is required, but ... is not a base class of ...
  • Doc fixed for Bugzilla 508: All members of an array need not be initialised
  • Doc fixed for Bugzilla 509: [wd]char[1] does not convert to [wd]char
  • Doc fixed for Bugzilla 510: Nonworking implicit conversions between arrays and pointers
  • Doc fixed for Bugzilla 511: Various problems in the documentation
  • Fixed Bugzilla 513: using struct initializer on static array crashes the compiler
  • Fixed Bugzilla 514: Misleading error message for static const initialisation
  • Fixed Bugzilla 517: std.compiler outdated
  • Fixed Bugzilla 521: frontend: incorrect error(Loc, const char*, char*) declaration in mars.h
  • Fixed Bugzilla 522: frontend: 64-bit format string cleanup
  • Fixed Bugzilla 524: Compiler crash when compiling
  • Fixed Bugzilla 530: segfault assigning array literal to a non-array const
  • Fixed Bugzilla 534: IPF trying to initialize an associative array
  • Fixed Bugzilla 550: Shifting by more bits than size of quantity is allowed
  • Fixed Bugzilla 554: Division by zero results in two identical errors
  • Fixed Bugzilla 555: Integral ireal literals can't be specified
  • Fixed Bugzilla 557: ICE returning a tuple from a function (Assertion failure: '0' on line 694 in file 'glue.c')
  • Fixed Bugzilla 560: Cannot escape reference to variadic parameter
  • Fixed Bugzilla 562: Source file without BOM starting with non-ASCII compiles and runs
  • Fixed Bugzilla 564: Setting predefined versions on the command line causes crashes
  • Fixed Bugzilla 567: Compiler crash with conflicting templates
  • Fixed Bugzilla 574: DMD uses D calling convention for returning complex floats from functions with C calling convention
  • Fixed Bugzilla 585: dmd crashes with segmentation fault
  • Fixed Bugzilla 587: DMD crashes compiling char[][] initialization
  • Fixed Bugzilla 589: std.string.newline should be char[] not char[2]
  • Fixed Bugzilla 591: version=LittleEndian crash the compiler
  • Fixed Bugzilla 593: can't deduce from arrayliteral
  • Fixed Bugzilla 597: std.socket TcpSocket and UdpSocket are missing.
  • Fixed Bugzilla 598: missing reentrant Linux functions
  • Fixed Bugzilla 610: Undocumented behaviour: ~ and ~= can now concatenate an array with a single element
  • Fixed Bugzilla 613: Error message still states that '===' and '!==' are merely deprecated
  • Fixed Bugzilla 618: The following program crashes dmd.exe 0.175
  • Fixed Bugzilla 619: Alias of templated struct instance crashes 0.175
Version D 0.175 Nov 25, 2006

New/Changed Features

  • Added == super to IsExpressions.
  • Class variables declared with scope are now allocated on the stack.

Bugs Fixed

  • Fixed Bugzilla 222: Internal error: ..\ztc\cod1.c 1656" with && and ||
  • Fixed Bugzilla 228: Crash on inferring function literal return type after prior errors
  • Fixed Bugzilla 311: Object files missing certain template instantiations
  • Fixed Bugzilla 331: performance bug in std.uni.toUniLower / std.uni.toUniUpper
  • Incorporated Bugzilla 332: typesafe variadic functions and lazy argument support for std.demangle
  • Fixed Bugzilla 343: Compile error using mixin containing struct
  • Fixed Bugzilla 349: Function matching with enums is erratic
  • Fixed Bugzilla 352: Assertion failure: expression.c 753 - concatenating strings in a template calling another template
  • Fixed Bugzilla 353: null passed as a char[] template argument, concatenated with a string literal, is a non-constant expression
  • Fixed Bugzilla 354: Internal error: e2ir.c 772 with bad template use
  • Fixed Bugzilla 355: ICE from enum : nonexistent type
  • Incorporated Bugzilla 363 XHTML support
  • Fixed Bugzilla 364: Mysterious access violation when using delegate()[1]... parameter
  • Fixed Bugzilla 373: Spec problems with TypeInfo: error and omission.
  • Fixed Bugzilla 378: Assertion failure: '0' on line 216 in file 'init.c'
  • Fixed Bugzilla 379: wrong thisptr type in typedef'ed struct
  • Fixed Bugzilla 380: cannot use typeof(*this) in a static context
  • Fixed Bugzilla 384: Different behaviour when compiling as separate object files
  • Fixed Bugzilla 389: Cannot link to std.path.altsep
  • Fixed Bugzilla 429: Unable to distinguish between empty and uninitialized dynamic arrays
  • Fixed Bugzilla 433: A deprecated, same-named alias screws up resolution of imports
  • Fixed Bugzilla 443: assignment in return when using cdouble is broken
  • Fixed Bugzilla 444: Inside a foreach with delegates, void return does not compile
  • Fixed Bugzilla 446: Anonymous class and "return without calling constructor"
  • Fixed Bugzilla 460: Assertion failure: '!needThis()' on line 143 in file 'tocsym.c'
  • Fixed Bugzilla 464: 64bit clean dchar.c
  • Fixed Bugzilla 465: errors when trying to use static templated methods
  • Fixed Bugzilla 466: dmd prevent this from link, if so please prevent it from compiling
  • Fixed Bugzilla 467: double inheritance from the same interface
  • Fixed Bugzilla 468: argument wrongfully identified as type in template instantiation
  • Fixed Bugzilla 471: Protection attributes of mixin instances are applied in a wrong scope.
  • Fixed Bugzilla 475: DMD segfault on recursive variadic template
  • Fixed Bugzilla 476: DMD doesn't resolve its location properly on Windows
  • Fixed Bugzilla 478: can't compare arrayliteral statically with variable
  • Fixed Bugzilla 480: too many initializers error message doesn't give line number
  • Fixed Bugzilla 486: Writefln on null object should not trigger access error.
  • Fixed Bugzilla 488: regression: recursive typeof segmentfaults
  • Fixed Bugzilla 490: Static struct initializer without static attribute aborts dmd with assertion
  • Fixed Bugzilla 525: can't use array variable in typetuple index
  • Fixed D.announce/5464
  • Fixed problem with ForStatement scope.
Version D 0.174 Nov 14, 2006

New/Changed Features

  • Implemented std.typetuple.
  • Implemented std.traits.
  • Added .funcptr property for delegates.
  • Added .tupleof property for structs and classes.
  • Slicing and indexing of type tuples now supported.
  • Variable declarations can now be declared with type tuples.
  • Improved the statement grammar thanks to Stewart Gordon.
  • Added DMD switch -v1 for D language 1.0 compatibility.
  • deprecated === and !== no longer allowed
  • deprecated iftype no longer allowed
  • deprecated on_scope_xxxx no longer allowed
  • deprecated 'l' numeric literal suffix no longer allowed
  • deprecated if (v; e) no longer allowed
  • deprecated instance no longer allowed
  • scope can now be used for RAII declarations; use auto for type inference.

Bugs Fixed

  • Fixed Bugzilla 462: invalid typeinfo usage breaks dmd compiler
  • Fixed Bugzilla 469: Incorrect documentation in std.date
  • Fixed Bugzilla 477: Malformed URL in documentation
  • Issues error now for Bugzilla 483: ICE-invalid with tuple. mangleof.
  • Fixed Bugzilla 484: Compiler segfault with template variadic used as a template alias
  • Fixed Bugzilla 489: .classinfo not working with fqn
  • Fixed Bugzilla 491: Create directories necessary for writing files when using -Dd and -Hd option
  • Fixed Bugzilla 494: template's variadic argument can't use as type
  • Fixed Bugzilla 495: ICE passing variadic arglist to another variadic template
  • Incorporated Bugzilla 496: frontend: 64-bit cleanup of utf_decode
  • Incorporated Bugzilla 497: frontend: 64-bit cleanup of sprintf buffer sizes
  • Fixed Bugzilla 498: Signal mixins need to import
  • Fixed Bugzilla 499: Multiple overrides of the destructor when using signals
  • Incorporated D/43595 suggestions
  • Fixed D/43649 crash
  • Fixed D.bugs/8856
  • Fixed D.announce/5290
Version D 0.173 Nov 1, 2006

New/Changed Features

  • Template instantiations can now accept alias parameters for local variables and nested functions.
  • Enhancement Bugzilla 333 std.c.locale
  • Implemented Signals and Slots.
  • Incorporated D.announce/5104 as std.cpuid.
  • Implemented variadic template parameters

Bugs Fixed

  • Fixed IFTI bug deducing types from struct templates
  • Fixed D/43122 crash
  • Fixed Bugzilla 445: debugging artifact: DeclarationExp::scanForNestedRef
  • Fixed/Incorporated Bugzilla 330: std.string.tolower / std.string.toupper broken for non-ASCII strings
  • Documented Bugzilla 350: Modulo for negative values is undefined
  • Incorporated Bugzilla 448: frontend: redefinition of size_t
  • Incorporated Bugzilla 449: frontend: html.h and complex_t.h are unprotected against multiple inclusion
  • Incorporated Bugzilla 450: frontend: please use <stdint.h> to increase portability
  • Incorporated Bugzilla 451: frontend: redundant function definitions
  • Fixed Bugzilla 457: notifyRelease: debugging artifacts
Version D 0.172 Oct 18, 2006

New/Changed Features

    Bugs Fixed

    • Fixed again Bugzilla 440: dmd.170 fails to mark final methods as implementations of abstract ones
    • Fixed Bugzilla 441: Crash on foreach of mixed-in aggregate
    • Fixed Bugzilla 442: Crash on foreach of mixed-in aggregate
    Version D 0.171 Oct 18, 2006

    New/Changed Features

      Bugs Fixed

      • Incorporating overlooked Bugzilla 429 change.
      • Fixed Bugzilla 440: dmd.170 fails to mark final methods as implementations of abstract ones
      Version D 0.170 Oct 17, 2006

      New/Changed Features

      • Added foreach_reverse.
      • Delegates can now be the 'aggregate' for the foreach.
      • final member functions that do not override any are no longer placed in the _vtbl[]. This means that code with classes deriving from such classes need to be recompiled.
      • null is now an exact match for null pointers, delegates, arrays, class objects, etc.

      Bugs Fixed

      • Fixed Bugzilla 407
      • Fixed Bugzilla 410
      • Fixed Bugzilla 411
      • Fixed Bugzilla 412
      • Fixed Bugzilla 414
      • Fixed Bugzilla 416
      • Incorporated Bugzilla 417
      • Fixed Bugzilla 418
      • Fixed Bugzilla 419
      • Fixed Bugzilla 420
      • Fixed Bugzilla 422
      • Fixed Bugzilla 426
      • Fixed Bugzilla 427
      • Fixed Bugzilla 428 (updated doc)
      • Incorporated Bugzilla 429
      • Fixed Bugzilla 430 (changed spec)
      • Fixed Bugzilla 431
      • Fixed Bugzilla 436
      Version D 0.169 Oct 7, 2006

      New/Changed Features

        Bugs Fixed

        • Improved optimization of div/mod combinations.
        • Fixed D/42668
        • Fixed D.announce/4869
        • Fixed D.bugs/8605
        • Fixed Bugzilla 351
        • Fixed Bugzilla 377
        • Fixed Bugzilla 381
        • Fixed Bugzilla 382
        • Fixed Bugzilla 386
        • Fixed Bugzilla 391
        • Fixed Bugzilla 394
        • Fixed Bugzilla 395, but there are probably more UTF bugs in std.regexp.
        • Fixed Bugzilla 396
        • Fixed Bugzilla 397
        • Fixed Bugzilla 402
        • Fixed Bugzilla 404
        • Fixed Bugzilla 405
        Version D 0.168 Oct 2, 2006

        New/Changed Features

        • Added .ptr property for delegates.
        • Added .outer property for nested class instances.
        • Can now initialize stack variables with array literals.
        • Array literals can now be cast to [][] types.
        • Mixins can now insert multiple destructors.

        Bugs Fixed

        • Fixed D.bugs/8408
        • Fixed Bugzilla 104
        • Fixed Bugzilla 291
        • Fixed Bugzilla 315
        • Fixed Bugzilla 347
        • Fixed Bugzilla 356
        • Incorporated Bugzilla 363
        • Fixed Bugzilla 365
        • Fixed Bugzilla 367
        • Fixed Bugzilla 368
        • Fixed Bugzilla 369
        • Fixed Bugzilla 370
        • Fixed Bugzilla 371
        • Fixed Bugzilla 372
        • Fixed Bugzilla 374
        • Fixed Bugzilla 385
        • Fixed Bugzilla 392
        Version D 0.167 Sep 18, 2006

        New/Changed Features

        • Implemented Stewart Gordon's suggestions per D.bugs/3843.
        • Added std.c.windows.stat.
        • Added std.file.getTimes().
        • Added support for multidimensional array allocation with NewExpression.
        • Added array literals.
        • std.format will now work with struct arguments as long as they define a char[] toString() member function.

        Bugs Fixed

        • Fixed dmd segfault on void inits of statics.
        • Fixed D.bugs/8247
        • Fixed Bugzilla 285
        • Fixed Bugzilla 289
        • Fixed Bugzilla 296
        • Fixed Bugzilla 297
        • Fixed Bugzilla 303
        • Fixed Bugzilla 308
        • Fixed Bugzilla 311
        • Fixed Bugzilla 324
        • Fixed Bugzilla 325
        • Fixed Bugzilla 326
        • Fixed Bugzilla 328
        • Fixed Bugzilla 329
        • Fixed Bugzilla 334
        • Fixed Bugzilla 335
        • Fixed Bugzilla 336
        • Fixed Bugzilla 344
        Version D 0.166 Aug 30, 2006

        New/Changed Features

        • Upgraded zlib from 1.2.1 to 1.2.3 per Bugzilla 286
        • Removed implicit conversion to delegates, except in the case of typesafe variadic arguments.
        • Replaced with lazy parameter storage class per Tomasz Stachowiak's suggestion D/41633.
        • Incorporated Oskar Linde's patches to support member templates.

        Bugs Fixed

        • Fixed Bugzilla 295
        • Fixed Bugzilla 300
        • Fixed Bugzilla 301
        • Fixed Bugzilla 304
        • Fixed Bugzilla 306
        Version D 0.165 Aug 20, 2006

        New/Changed Features

        • Added implicit conversion of expressions to delegates.

        Bugs Fixed

        • Fixed Bugzilla 170
        • Fixed Bugzilla 292
        • Fixed dstress class_26_A and dstress class_26_B
        Version D 0.164 Aug 11, 2006

        New/Changed Features

        • Added DDOC_COMMENT macro to Ddoc.

        Bugs Fixed

        • Added a couple needed publics to std.thread per Dave Fladebo
        • Fixed D.bugs/7923
        • Fixed D.bugs/7928
        • Fixed D.bugs/8028
        • Fixed dstress mangleof_16_A
        • Fixed dstress bug_cgcod_1667_A
        • Fixed dstress bug_type_308_B
        • Fixed Bugzilla 256 (revised documentation to reflect intended behavior)
        • Fixed Bugzilla 262 (added suggested documentation)
        • Fixed Bugzilla 264 (made static import with bind list illegal)
        • Fixed Bugzilla 269
        • Fixed Bugzilla 270
        • Fixed Bugzilla 272
        • Fixed Bugzilla 273
        • Fixed Bugzilla 274
        • Fixed Bugzilla 276
        • Fixed Bugzilla 278
        • Fixed Bugzilla 279
        Version D 0.163 Jul 18, 2006

        New/Changed Features

        • Object.opCmp now throws an error. Should override it if used. Breaks existing code.
        • Imports now default to private instead of public. Breaks existing code.
        • Added static imports, renamed imports, and selective importing.

        Bugs Fixed

        • Added documentation per Stewart Gordon's suggestion D/21572
          • .
        • Fixed Bugzilla 232
        • Fixed Bugzilla 236
        • Fixed Bugzilla 239
        • Fixed Bugzilla 240
        • Fixed Bugzilla 241
        • Fixed Bugzilla 246
        • Fixed Bugzilla 247
        • Fixed Bugzilla 248
        • Fixed Bugzilla 249
        • Fixed Bugzilla 250
        • Private module members now inaccessible from other modules.
        Version D 0.162 Jun 22, 2006

        New/Changed Features

          Bugs Fixed

          • Fixed D.bugs/7620
          • Fixed D.bugs/7627
          • Fixed D.bugs/7630
          • Fixed Bugzilla 125
          • Fixed Bugzilla 135
          • Fixed Bugzilla 138
          • Fixed Bugzilla 145
          • Fixed Bugzilla 147
          • Fixed Bugzilla 154
          • Fixed Bugzilla 155
          • Fixed Bugzilla 167
          • Fixed Bugzilla 172
          • Fixed Bugzilla 179 (first example is an error now diagnosed, following two now work correctly)
          • Fixed Bugzilla 180
          • Fixed Bugzilla 181 (changed documentation)
          • Fixed Bugzilla 184
          • Fixed Bugzilla 185
          • Fixed Bugzilla 193
          • Fixed Bugzilla 197
          • Fixed Bugzilla 200 (changed spec to allow ';' as empty statement for labelled statement)
          • Fixed Bugzilla 205
          • Fixed Bugzilla 210
          • Fixed Bugzilla 225
          Version D 0.161 Jun 19, 2006

          New/Changed Features

          • Added opIn_r operator overload.
          • Function return types for lambda delegates can now be inferred.
          • delegate keyword now optional for lambda delegates.
          • Shadowing local variable declarations is now deprecated.
          • New function template syntax.

          Bugs Fixed

          • Fixed D.bugs/5957
          • Fixed D.bugs/5958
          • Fixed D.bugs/7399
          • Folded in D.bugs/7509
          • Fixed D.bugs/7518
          • Fixed Bugzilla 14 (fixed documentation to explain error)
          • Fixed Bugzilla 29
          • Fixed Bugzilla 34
          • Fixed Bugzilla 36 (better error message)
          • Fixed Bugzilla 47
          • Fixed Bugzilla 51 according to Bruno's analysis
          • Fixed Bugzilla 57 in 0.151
          • Fixed Bugzilla 59
          • Fixed Bugzilla 74
          • Fixed Bugzilla 75
          • Fixed Bugzilla 76
          • Fixed Bugzilla 85 (now issues error message)
          • Fixed Bugzilla 96 (fixed documentation)
          • Fixed Bugzilla 103
          • Fixed Bugzilla 106
          • Fixed Bugzilla 113 (thanks to Artem Rebrov)
          • Fixed Bugzilla 116 (use offsetof rather than offset)
          • Fixed Bugzilla 119
          • Fixed Bugzilla 120
          • Fixed Bugzilla 123
          • Fixed Bugzilla 128
          • Fixed Bugzilla 130
          • Fixed Bugzilla 134 (again)
          • Fixed Bugzilla 159 (better error message)
          • Fixed Bugzilla 160
          • Fixed Bugzilla 192
          • Fixed Bugzilla 202
          Version D 0.160 Jun 4, 2006

          New/Changed Features

          • Documentation is much more controlled by style sheets now.
          • AssertExpression's can now take an optional informational string as the second parameter. Static assert's can, too.
          • Added Expression.NewExpression so inner classes can be initialized more conveniently.
          • Added operator overloading of InExpression.
          • For Windows, looks for sc.ini in:
            1. The current working directory
            2. The directory specified by the HOME environment variable
            3. The directory dmd.exe resides in
          • For Linux, looks for dmd.conf in:
            1. The current working directory
            2. The directory specified by the HOME environment variable
            3. directory dmd resides in
            4. /etc/

          Bugs Fixed

          • Fixed Bugzilla 50, but the o must appear as o.new Inner
          • Fixed Bugzilla 139
          • Fixed Bugzilla 148
          • Fixed Bugzilla 149
          • Fixed Bugzilla 156
          • Fixed Bugzilla 158
          • Fixed Bugzilla 168
          • Fixed Bugzilla 173
          • Incorporated Artem Rebrov's fix D.bugs/7345
          • Line number debug info now generated for inline asm.
          Version D 0.159 May 26, 2006

          New/Changed Features

            Bugs Fixed

            • Fixed Bugzilla 134 (again!)
            • Fixed D.bugs/7325
            Version D 0.158 May 22, 2006

            New/Changed Features

            • Added DDOC_DITTO Ddoc macro to address D.bugs/7152.
            • Ddoc now emits module COPYRIGHT macro by default to address D.bugs/7148.
            • dmd now lists -gc switch to address D.bugs/7187.
            • For Bugzilla 77, dmd now stops after first static assert error, and before template expansions after errors.

            Bugs Fixed

            • Fixed Bugzilla 44
            • Fixed Bugzilla 54
            • Fixed Bugzilla 65, including dstress interface_23_D.d
            • Fixed Bugzilla 79
            • Fixed Bugzilla 83
            • Fixed Bugzilla 89
            • Fixed Bugzilla 97
            • Fixed Bugzilla 108
            • Fixed Bugzilla 110
            • Fixed Bugzilla 115
            • Fixed Bugzilla 118
            • Fixed Bugzilla 121
            • Fixed Bugzilla 126
            • Fixed Bugzilla 127
            • Fixed Bugzilla 132
            • Fixed Bugzilla 133
            • Fixed Bugzilla 134
            • Fixed Bugzilla 141
            • Fixed Bugzilla 142
            • Fixed Bugzilla 151
            • Fixed Bugzilla 153
            • Fixed D.bugs/7147
            • Fixed D.bugs/7191
            • Fixed D.bugs/7204
            • Fixed D.bugs/7218
            • Fixed c++.beta/512
            • Fixed Dstress bug_cg87_2393_A
            • Added -m32 to linux link per D.bugs/7264
            Version D 0.157 May 10, 2006

            New/Changed Features

            • Partial Dwarf symbol debug info now generated for Linux.
            • Improved dumpobj's handling of Dwarf symbolic debug info.

            Bugs Fixed

            • Applied Dave Fladebo's fix to gc internal sorting problem.
            Version D 0.156 Apr 28, 2006

            Bugs Fixed

            • Fixed Bugzilla 117
            Version D 0.155 Apr 27, 2006

            New/Changed Features

            • Added Microsoft windbg.exe Win32 debugger.
            • Removed std.recls, instead use http://synesis.com.au/software/recls/.
            • Incorporated Dave Fladebo's changes:
              • std.regexp speedups.
              • Fixed a bug in pauseHandler whereby the stackTop was being overwritten by subsequently resumed threads causing a crash in gcx.mark(). (The fix was to just move sem_post(&flagSuspend); to right before the sigsuspend loop).
              • Moved linux semaphore declarations to std/c/linux/linux.d
              • Changed void wait(uint milliseconds){} to be a timed wait function instead of just a stub for void wait() {} on linux (it is comparable to the Win32 Thread method now). This is implemented with pthread mutexes and conditions and the extra overhead to initialize phobos Threads does not result in slower executables (Threads, GC and startup time are not effected).
              • Changed the allThreads static array size to the same as Windows. This in conjunction w/ the stack size change will allow the creation of more than 100 threads on linux for better compatibility w/ the Win32 version.
              • Added optional stack size parameter to constructors. Since the stackBottom is static when the threads are created and the stackTop is dynamic based on the stack pointer (or context for Win32), allowing the threads to be created with a non-default stack size shouldn't interfere with the GC. This adds little overhead to either the Win32 or Linux Thread implementations.

            Bugs Fixed

            • Fixed D.bugs/7029
            • Fixed D.bugs/7043
            • Fixed Bugzilla 10
            • Fixed Bugzilla 13
            • Fixed Bugzilla 15
            • Fixed Bugzilla 23
            • Fixed Bugzilla 30
            • Fixed Bugzilla 33
            • Fixed Bugzilla 35
            • Fixed Bugzilla 105
            Version D 0.154 Apr 11, 2006

            New/Changed Features

            • Numeric suffix 'l' now deprecated, use 'L' instead.
            • Floating point suffix 'I' now deprecated, use 'i' instead.

            Bugs Fixed

            • Removed --gc_sections, it causes exception handling to fail.
            Version D 0.153 Apr 7, 2006

            New/Changed Features

            • Changed parameter types for std.date.MakeDate and std.date.MakeTime so they won't overflow.
            • Changed arraycat per suggestion D.announce/3400.
            • Added -nofloat compiler switch to suppress generation of __fltused reference by library code (Windows only).
            • dmd for Linux now adds --gc-sections switch to the link step to enable smart linking.
            • Nested functions now are placed in their own distinct code sections to facilitate smart linking.

            Bugs Fixed

            • Removed floating point dependency from std.date.
            • Fixed Bugzilla 45
            • Fixed Bugzilla 84
            • Fixed Bugzilla 86
            • Fixed Bugzilla 87
            • Fixed Bugzilla 90
            • Fixed Bugzilla 92
            • Fixed Bugzilla 94
            • Fixed Bugzilla 95
            Version D 0.152 Apr 3, 2006

            Bugs Fixed

            • Non-debug phobos.lib build included.
            Version D 0.151 Apr 2, 2006

            New/Changed Features

            • Changed the hash type from uint to hash_t. This will make 64 bit implementations better.

            Bugs Fixed

            • Fixed D/35845
            • Fixed D.bugs/6662
            • Fixed D.bugs/6743
            • Fixed D.bugs/6823
            • Fixed D.bugs/6838 (now diagnoses an error at compile time)
            • Fixed Bugzilla 55
            • Fixed Bugzilla 56
            • Fixed Bugzilla 57
            • Fixed Bugzilla 58
            • Cannot reproduce Bugzilla 60
            • Fixed Bugzilla 61
            • Fixed Bugzilla 62
            • Fixed Bugzilla 65
            • Fixed Bugzilla 66
            • Fixed Bugzilla 67
            • Fixed Bugzilla 73
            Version D 0.150 Mar 18, 2006

            New/Changed Features

            • Implicit conversion of reals and imaginaries to complex is no longer allowed per Don Clugston's suggestion.
            • Moved string.h functions from std.string to std.c.string.
            • Now supports covariant interface method returns.

            Bugs Fixed

            • Fixed Ddoc problem with auto declarations.
            • Fixed Ddoc problem with extern (C) function formatting.
            • Fixed Internal error: cg87 1297
            • Fixed D.bugs/6425
            • Fixed D.bugs/6533
            • Fixed D.bugs/6547
            • Fixed Bugzilla 5
            • Fixed Bugzilla 17
            • Fixed Bugzilla 19
            • Fixed Bugzilla 20
            • Fixed Bugzilla 25
            • Fixed Bugzilla 26
            • Fixed Bugzilla 27
            Version D 0.149 Mar 7, 2006

            New/Changed Features

            • Changed on_scope_exit to scope(exit)
            • Changed on_scope_success to scope(success)
            • Changed on_scope_failure to scope(failure)
            • Changed IfStatement to allow: (auto v = expression), and (type v = expression) forms.
            • & | ^ &= |= ^= ! && || ?: are now only operators allowed on bools
            • opSliceAssign now overloads assignment to a slice.
            • Added std.c.fenv.
            • Added limited support for implicit function template instantiation.

            Bugs Fixed

            • Fixed bit problem with phobos\internal\gc\gcbits.d
            • Fixed D.bugs/6399
            • Fixed D.bugs/6419
            • Implicit casts of non-bool to bool disallowed
            • Fixed code gen bugs for OnScopeGuardStatements.
            Version D 0.148 Feb 25, 2006

            New/Changed Features

            • Removed MatchExpressions.
            • foreach loops can now implicitly determine the types in the ForeachTypelist.
            • IfStatements can now have an optional variable implicitly declared and assigned the value of the Expression.
            • Removed bit basic type.
            • Added bool basic type.
            • Added BitArray.
            • Added On Scope Statements.

            Bugs Fixed

            • Fixed D.bugs/6277
            • Fixed D.bugs/6280
            • Fixed D.bugs/6288
            • Fixed D.bugs/6301
            • Fixed D.bugs/6302
            • Fixed D.bugs/6303
            • Fixed D.bugs/6304
            • Fixed D.bugs/6305
            • Fixed D.bugs/6327
            • Fixed D.bugs/6333
            Version D 0.147 Feb 12, 2006

            New/Changed Features

            • Renamed std.regexp.RegExpError to RegExpException.
            • -run switch changed so that the source file to compile must appear immediately after it.
            • Added MatchExpressions
              • .

            Bugs Fixed

            • Incorporated Dave Fladebo's fixes for std.process.spawnvp() on Linux.
            • Fixed D.bugs/6196
            • Fixed D.bugs/6225
            • Fixed D.bugs/6231
            • Fixed D.bugs/6238
            • Fixed D.bugs/6251
            • Fixed D.bugs/6252
            • Fixed D.bugs/6260
            • Fixed D.bugs/6264
            • Fixed D/33201
            Version D 0.146 Feb 9, 2006

            New/Changed Features

            • Improvements to the functionality of std.file.listdir().
            • Removed the long-deprecated instance keyword.
            • Ignores first line starting with #!, D/32661.
            • Added -run command line switch.
            • Added module statements to all std.typeinfo modules. This may require recompiling library code.

            Bugs Fixed

            • Fixed D/32444
            • Fixed D.bugs/4829
            • Fixed D.bugs/5851, D.bugs/2677, D.bugs/2853, D/13127
            • Fixed D.bugs/6122
            • Fixed D.bugs/6141
            • Fixed D.bugs/6150
            • Fixed D.bugs/6168
            • Fixed D.bugs/6186
            • Fixed std.math.poly() for Linux
            • Fixed header gen bugs reported by Dave Fladebo
            Version D 0.145 Jan 29, 2006

            New/Changed Features

            Bugs Fixed

            • Incorporated D/32417
            • Fixed D.bugs/6068
            • Fixed D.bugs/6079
            • Fixed D.bugs/6080
            • Fixed D.bugs/6081
            • Fixed D.bugs/6082
            • Fixed D.bugs/6097
            • Fixed D.bugs/6099
            • Fixed D.bugs/6105
            • Fixed several problems with -fPIC code generation
            • Fixed dstress const_04 regression
            • Fixed dstress asm_lea_01_B regression
            • Fixed D.announce/2578
            • Fixed problem with abstract template classes
            Version D 0.144 Jan 22, 2006

            New/Changed Features

            • static if now can reference declarations in same scope.
            • Leading . no longer necessary for recursive template instantiations.

            Bugs Fixed

            • Constant folding of string==string now works.
            • Constant folding of length for char literals now works.
            • Constant folding of char literals appending chars now works.
            • Constant folding of char literal slices now works.
            • Fixed D.bugs/6003
            • Fixed D.bugs/6018
            • Fixed D.bugs/6027
            • Fixed D.bugs/6049
            Version D 0.143 Jan 9, 2006

            New/Changed Features

            • Added D.bugs/5987 std.path.expandTilde() by Grzegorz Adam Hankiewicz and Thomas Kuehne.
            • Added Don Clugston's improvements to std.math in D/31951.

            Bugs Fixed

            • Fixed D.announce/2303
            • Fixed D.announce/2315
            • Fixed D.bugs/5910
            • Fixed D.bugs/5917
            • Fixed D.bugs/5924
            • Fixed D.bugs/5937
            • Fixed D.bugs/5939
            • Fixed D.bugs/5950
            • Fixed D.bugs/5970
            • Fixed D.bugs/5981
            • Fixed D.bugs/5983
            • Per Grzegorz Adam Hankiewicz's suggestions in D.bugs/5984, Windows only declarations in process.d are versioned.
            Version D 0.142 Dec 28, 2005

            New/Changed Features

            • AssertError now has a destructor, per proposal in D/31595.
            • Added D interface file support, with much help from Dave Fladebo.

            Bugs Fixed

            • Fixed D.bugs/5749
            • Fixed D.bugs/5771
            • Fixed D.bugs/5772
            • Fixed D.bugs/5773
            • Fixed D.bugs/5809
            • Fixed D/31482
            Version D 0.141 Dec 4, 2005

            New/Changed Features

            • The predefined version identifier D_InlineAsm has been changed to D_InlineAsm_X86. The former made no sense, and although it is still defined, it is deprecated.
            • Added D code coverage analyzer.
            • Added .mangleof property for types, which gives the 'mangled' type name as a string.

            Bugs Fixed

            • Fixed D.bugs/5643
            • Fixed D.bugs/5668
            • Fixed D.bugs/5687
            • Fixed D.bugs/5690
            • Fixed D.bugs/5673 (it now issues an OutOfMemoryException)
            • Fixed D.bugs/5729
            • Fixed dstress.run.c.creal_26_A regression.
            • Fixed dstress.run.const_18 regression.
            Version D 0.140 Nov 23, 2005

            New/Changed Features

            • Added std.string.soundex.
            • Added std.string.entab.
            • Added std.string.wrap.
            • Added std.string.abbrev.
            • Added std.windows.charset (thanks to Stewart Gordon, D/28426).
            • Added std.demangle to demangle D names.
            • Improved promotion of names inside templates.
            • Now allows floating point and string literals as template value arguments.
            • To support the previous, the name mangling of template instances has changed. This will necessitate recompilation of any code that uses templates.
            • std.utf.UtfError is now deprecated. Use std.utf.UtfException instead.

            Bugs Fixed

            • Fixed D.bugs/5299
            • Fixed D.bugs/5353
            • Fixed D.bugs/5360
            • Fixed D.bugs/5391
            • Fixed D.bugs/5429
            • Fixed D.bugs/5464
            • Fixed std.string.expandtabs so it handles UTF.


Downloads

  • dmd.zip (D compiler) for Win32 and Linux
  • dmc.zip (linker and utilities) for Win32
  • GDC - D Programming Language for GCC
  • Mac OS X version of GDC
  • DMDScript source
  • Empire 2.01 source

Copyright © 1999-2007 by Digital Mars, All Rights Reserved | Page generated by Ddoc. | Comments


Not Written Yet

 [Home] [Search]

Sorry, this section is not written yet!

Copyright (c) 1999-2001 by Digital Mars, All Rights Reserved


std.windows.registry

\file std/windows/registry.d This file contains the \c std.windows.registry.* classes

alias boolean;
A strongly-typed Boolean

enum Endian;
An enumeration representing byte-ordering (Endian) strategies

enum REGSAM;
Enumeration of the recognised registry access modes

\ingroup group_D_win32_reg

enum REG_VALUE_TYPE;
Enumeration of the recognised registry value types

\ingroup group_D_win32_reg

class RegistryException: std.windows.registry.Win32Exception;
Exception class thrown by the std.windows.registry classes

\ingroup group_D_win32_reg

this(string message);
\brief Creates an instance of the exception

\param message The message associated with the exception \name Construction

this(string message, int error);
\brief Creates an instance of the exception, with the given

\param message The message associated with the exception \param error The Win32 error number associated with the exception \name Construction

class Key;
This class represents a registry key

\ingroup group_D_win32_reg

string name();
The name of the key \name Attributes \name Construction

uint keyCount();
The number of sub keys \name Attributes \name Construction

KeySequence keys();
An enumerable sequence of all the sub-keys of this key \name Attributes \name Construction

KeyNameSequence keyNames();
An enumerable sequence of the names of all the sub-keys of this key \name Attributes \name Construction

uint valueCount();
The number of values \name Attributes \name Construction

ValueSequence values();
An enumerable sequence of all the values of this key \name Attributes \name Construction

ValueNameSequence valueNames();
An enumerable sequence of the names of all the values of this key \name Attributes \name Construction

Key createKey(string name, REGSAM access);
Returns the named sub-key of this key

\param name The name of the subkey to create. May not be null \return The created key \note If the key cannot be created, a RegistryException is thrown. \name Methods \name Attributes \name Construction

Key createKey(string name);
Returns the named sub-key of this key

\param name The name of the subkey to create. May not be null \return The created key \note If the key cannot be created, a RegistryException is thrown. \note This function is equivalent to calling CreateKey(name, REGSAM.KEY_ALL_ACCESS), and returns a key with all access \name Methods \name Attributes \name Construction

Key getKey(string name, REGSAM access);
Returns the named sub-key of this key

\param name The name of the subkey to aquire. If name is null (or the empty-string), then the called key is duplicated \param access The desired access; one of the REGSAM enumeration \return The aquired key. \note This function never returns null. If a key corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

Key getKey(string name);
Returns the named sub-key of this key

\param name The name of the subkey to aquire. If name is null (or the empty-string), then the called key is duplicated \return The aquired key. \note This function never returns null. If a key corresponding to the requested name is not found, a RegistryException is thrown \note This function is equivalent to calling GetKey(name, REGSAM.KEY_READ), and returns a key with read/enum access \name Methods \name Attributes \name Construction

void deleteKey(string name);
Deletes the named key

\param name The name of the key to delete. May not be null \name Methods \name Attributes \name Construction

Value getValue(string name);
Returns the named value

\note if name is null (or the empty-string), then the default value is returned \return This function never returns null. If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, uint value);
Sets the named value with the given 32-bit unsigned integer value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The 32-bit unsigned value to set \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, uint value, Endian endian);
Sets the named value with the given 32-bit unsigned integer value, according to the desired byte-ordering

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The 32-bit unsigned value to set \param endian Can be Endian.Big or Endian.Little \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, ulong value);
Sets the named value with the given 64-bit unsigned integer value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The 64-bit unsigned value to set \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, string value);
Sets the named value with the given string value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The string value to set \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, string value, boolean asEXPAND_SZ);
Sets the named value with the given string value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The string value to set \param asEXPAND_SZ If true, the value will be stored as an expandable environment string, otherwise as a normal string \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, string[] value);
Sets the named value with the given multiple-strings value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The multiple-strings value to set \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void setValue(string name, byte[] value);
Sets the named value with the given binary value

\param name The name of the value to set. If null, or the empty string, sets the default value \param value The binary value to set \note If a value corresponding to the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void deleteValue(string name);
Deletes the named value

\param name The name of the value to delete. May not be null \note If a value of the requested name is not found, a RegistryException is thrown \name Methods \name Attributes \name Construction

void flush();
Flushes any changes to the key to disk

\name Methods \name Attributes \name Construction

class Value;
This class represents a value of a registry key

\ingroup group_D_win32_reg

string name();
The name of the value.

\note If the value represents a default value of a key, which has no name, the returned string will be of zero length \name Attributes

REG_VALUE_TYPE type();
The type of value \name Attributes

string value_SZ();
Obtains the current value of the value as a string.

\return The contents of the value \note If the value's type is REG_EXPAND_SZ the returned value is not expanded; Value_EXPAND_SZ() should be called \note Throws a RegistryException if the type of the value is not REG_SZ, REG_EXPAND_SZ, REG_DWORD(*) or REG_QWORD(*): \name Attributes

string value_EXPAND_SZ();
Obtains the current value as a string, within which any environment variables have undergone expansion

\return The contents of the value \note This function works with the same value-types as Value_SZ(). \name Attributes

string[] value_MULTI_SZ();
Obtains the current value as an array of strings

\return The contents of the value \note Throws a RegistryException if the type of the value is not REG_MULTI_SZ \name Attributes

uint value_DWORD();
Obtains the current value as a 32-bit unsigned integer, ordered correctly according to the current architecture

\return The contents of the value \note An exception is thrown for all types other than REG_DWORD, REG_DWORD_LITTLE_ENDIAN and REG_DWORD_BIG_ENDIAN. \name Attributes

deprecated uint value_DWORD_LITTLEENDIAN();
\name Attributes

deprecated uint value_DWORD_BIGENDIAN();
\name Attributes

ulong value_QWORD();
Obtains the value as a 64-bit unsigned integer, ordered correctly according to the current architecture

\return The contents of the value \note Throws a RegistryException if the type of the value is not REG_QWORD \name Attributes

deprecated ulong value_QWORD_LITTLEENDIAN();
\name Attributes

byte[] value_BINARY();
Obtains the value as a binary blob

\return The contents of the value \note Throws a RegistryException if the type of the value is not REG_BINARY \name Attributes

class Registry;
Represents the local system registry.

\ingroup group_D_win32_reg

static Key classesRoot();
Returns the root key for the HKEY_CLASSES_ROOT hive \name Hives

static Key currentUser();
Returns the root key for the HKEY_CURRENT_USER hive \name Hives

static Key localMachine();
Returns the root key for the HKEY_LOCAL_MACHINE hive \name Hives

static Key users();
Returns the root key for the HKEY_USERS hive \name Hives

static Key performanceData();
Returns the root key for the HKEY_PERFORMANCE_DATA hive \name Hives

static Key currentConfig();
Returns the root key for the HKEY_CURRENT_CONFIG hive \name Hives

static Key dynData();
Returns the root key for the HKEY_DYN_DATA hive \name Hives

class KeyNameSequence;
An enumerable sequence representing the names of the sub-keys of a registry Key

It would be used as follows:

  Key key = . . .

  foreach(char[] kName; key.SubKeys)
  {
    process_Key(kName);
  }

\ingroup group_D_win32_reg

uint count();
The number of keys \name Attributes @{ Construction

string getKeyName(uint index);
The name of the key at the given index

\param index The 0-based index of the key to retrieve \return The name of the key corresponding to the given index \note Throws a RegistryException if no corresponding key is retrieved \name Attributes @{ Construction

string opIndex(uint index);
The name of the key at the given index

\param index The 0-based index of the key to retrieve \return The name of the key corresponding to the given index \note Throws a RegistryException if no corresponding key is retrieved \name Attributes @{ Construction

int opApply(int delegate(ref char[] name) dg);
@} \name Attributes @{ Construction

class KeySequence;
An enumerable sequence representing the sub-keys of a registry Key

It would be used as follows:

  Key key = . . .

  foreach(Key k; key.SubKeys)
  {
    process_Key(k);
  }

\ingroup group_D_win32_reg

uint count();
The number of keys \name Attributes @{ Construction

Key getKey(uint index);
The key at the given index

\param index The 0-based index of the key to retrieve \return The key corresponding to the given index \note Throws a RegistryException if no corresponding key is retrieved \name Attributes @{ Construction

Key opIndex(uint index);
The key at the given index

\param index The 0-based index of the key to retrieve \return The key corresponding to the given index \note Throws a RegistryException if no corresponding key is retrieved \name Attributes @{ Construction

int opApply(int delegate(ref Key key) dg);
@} \name Attributes @{ Construction

class ValueNameSequence;
An enumerable sequence representing the names of the values of a registry Key

It would be used as follows:

  Key key = . . .

  foreach(char[] vName; key.Values)
  {
    process_Value(vName);
  }

\ingroup group_D_win32_reg

uint count();
The number of values \name Attributes @{ Construction

string getValueName(uint index);
The name of the value at the given index

\param index The 0-based index of the value to retrieve \return The name of the value corresponding to the given index \note Throws a RegistryException if no corresponding value is retrieved \name Attributes @{ Construction

string opIndex(uint index);
The name of the value at the given index

\param index The 0-based index of the value to retrieve \return The name of the value corresponding to the given index \note Throws a RegistryException if no corresponding value is retrieved \name Attributes @{ Construction

int opApply(int delegate(ref char[] name) dg);
@} \name Attributes @{ Construction

class ValueSequence;
An enumerable sequence representing the values of a registry Key

It would be used as follows:

  Key key = . . .

  foreach(Value v; key.Values)
  {
    process_Value(v);
  }

\ingroup group_D_win32_reg

uint count();
The number of values \name Attributes @{ Construction

Value getValue(uint index);
The value at the given index

\param index The 0-based index of the value to retrieve \return The value corresponding to the given index \note Throws a RegistryException if no corresponding value is retrieved \name Attributes @{ Construction

Value opIndex(uint index);
The value at the given index

\param index The 0-based index of the value to retrieve \return The value corresponding to the given index \note Throws a RegistryException if no corresponding value is retrieved \name Attributes @{ Construction

int opApply(int delegate(ref Value value) dg);
@} \name Attributes @{ Construction

Copyright © 1999-2012 by Digital Mars, All Rights Reserved | Page generated by Ddoc.