Intro

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

D Programming Language 2.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 1 which is in maintenance mode.
  2. D version 2 which is recommended for new projects.

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. 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
        int 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 int _argc;
    private string _argv;

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

    int 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-2010 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc.


Overview

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

Overview

What is D?

D is a general purpose systems and applications programming language. It is a high level language, 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++ 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 Design Goals of D

Everything in designing a language is a tradeoff. Keeping some principles in mind will help to make the right decisions.

  1. Make it easier to write code that is portable from compiler to compiler, machine to machine, and operating system to operating system. Eliminate undefined and implementation defined behaviors as much as practical.
  2. Provide syntactic and semantic constructs that eliminate or at least reduce common mistakes. Reduce or even eliminate the need for third party static code checkers.
  3. Support memory safe programming.
  4. Support multi-paradigm programming, i.e. at a minimum support imperative, structured, object oriented, generic and even functional programming paradigms.
  5. Make doing things the right way easier than the wrong way.
  6. Have a short learning curve for programmers comfortable with programming in C, C++ or Java.
  7. Provide low level bare metal access as required. Provide a means for the advanced programmer to escape checking as necessary.
  8. Make D reasonably easy to implement a compiler for.
  9. Be compatible with the local C application binary interface.
  10. Where D code looks the same as C code, have it either behave the same or issue an error.
  11. Have a context-free grammar. Successful parsing must not require semantic analysis.
  12. Easily support writing internationalized applications.
  13. Incorporate Contract Programming and unit testing methodology.
  14. Be able to build lightweight, standalone programs.
  15. Reduce the costs of creating documentation.
  16. Provide sufficient semantics to enable advances in compiler optimization technology.
  17. Cater to the needs of numerical analysis programmers.
  18. Obviously, sometimes these goals will conflict. Resolution will be in favor of usability.

Features To Keep

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.

Functional Programming

Functional programming has a lot to offer in terms of encapsulation, concurrent programming, memory safety, and composition. D's support for functional style programming include:

  • Pure functions
  • Immutable types and data structures
  • Lambda functions and closures

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.

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;
}

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


Windows

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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 \dmd2\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 core.runtime;
import std.c.windows.windows;

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

    void exceptionHandler(Exception e)
    {
    throw e;
    }

    try
    {
    Runtime.initialize(&exceptionHandler);

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

    Runtime.terminate(&exceptionHandler);
    }

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

    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.

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


Writing Win32 DLLs

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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;
import core.dll_helper;

__gshared HINSTANCE g_hInst;

extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
    switch (ulReason)
    {
    case DLL_PROCESS_ATTACH:
        g_hInst = hInstance;
        dll_process_attach( hInstance, true );
        break;

    case DLL_PROCESS_DETACH:
        dll_process_detach( hInstance, true );
        break;

    case DLL_THREAD_ATTACH:
        dll_thread_attach( true, true );
        break;

    case DLL_THREAD_DETACH:
        dll_thread_detach( true, true );
        break;
    }
    return true;
}

Notes:

  • DllMain simply forwards to the appropriate helper functions. These setup the runtime, create thread objects for interaction with the garbage collector and initialize thread local storage data.
  • The DLL does not share its runtime or memory with other DLLs.
  • The first boolean argument to the dll-helper functions specify whether all threads should be controlled by the garbage collector. You might need more control over this behaviour if there are threads in the process that must not be suspended. In this case pass false to disable the automatic handling of all threads.
  • 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            WRITE

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:

mydll.d:

module mydll;
import std.c.stdio;
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 -L/IMPLIB mydll.d dll.d mydll.def
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 an interface file mydll.di that doesn't have the function bodies:

mydll.di:

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.
  • Notify the GC about external references to a memory block by calling GC.addRange.
  • 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 core.runtime;
import std.c.stdio;
import std.c.stdlib;
import std.string;
import std.c.windows.windows;

HINSTANCE   g_hInst;

extern (C)
{
    void  gc_setProxy(void* p);
    void  gc_clrProxy();
}

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

        case DLL_PROCESS_DETACH:
        printf("DLL_PROCESS_DETACH\n");
        Runtime.terminate();
        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");
    gc_setProxy(gc);
}

export void MyDLL_Terminate()
{
    printf("MyDLL_Terminate()\n");
    gc_clrProxy();
}

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 is in this version as well. This is because the same DLL should be usable from both C and D programs, so the same initialization process should work for both.

MyDLL_Initialize
When the DLL is dynamically linked via Runtime.loadLibrary() the runtime makes sure that any initialization steps required by the D program are executed after the library is loaded. If the library is statically linked, this routine is not called by the program, so to make sure the DLL is initialized properly we have to do some of the work ourselves. And because the library is being statically linked, we need a function specific to this DLL to perform the initialization. This function takes one argument, a handle to the caller's gc. We'll see how that handle is obtained later. To pass this handle to the runtime and override the DLL's built-in gc we'll call gc_setProxy(). 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 only one job: informing the runtime that the DLL will no longer be using the caller's gc via gc_clrProxy(). This 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 mydll.def -g -L/map
    Links mydll.obj into a DLL named mydll.dll. 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 core.runtime;
import std.stdio;
import std.gc;

import mydll;

//version=DYNAMIC_LOAD;

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

    alias MyClass function() getMyClass_fp;

    int main()
    {   HMODULE h;
        FARPROC fp;

        getMyClass_fp getMyClass;
        MyClass c;

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

        h = cast(HMODULE) Runtime.loadLibrary("mydll.dll");
        if (h is null)
        {
            printf("error loading mydll.dll\n");
            return 1;
        }

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

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

        if (!Runtime.unloadLibrary(h))
        {   printf("error freeing mydll.dll\n");
            return 1;
        }

        printf("End...\n");
        return 0;
    }
}
else
{   // static link the DLL
    extern (C)
    {
        void* gc_getProxy();
    }

    int main()
    {
    printf("Start Static Link...\n");
    MyDLL_Initialize(gc_getProxy());
    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 Runtime.loadLibrary(), 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 Runtime.unloadLibrary().

Running it looks like this:

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

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


COM Programming

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

COM Programming

COM interfaces are all derived from std.c.windows.com.IUnknown.

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


Converting C .h Files to D Modules

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Fri Nov 26 11:09:41 2010

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 type modifier.
void foo(const int *p, char *const q);
becomes:
void foo(const int* p, const char* q);

But D's const is transitive - there are no const pointers to mutable types in D. When encountering such in C code, simply drop the const.

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.

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


D 2.0 FAQ

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

D 2.0 FAQ

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

D 1.0 FAQ

C++ FAQ

D 2.0 FAQ

  • What's the difference between D 2.0 and D 1.0?
  • Where is my simple language?
  • What's D 2.0's answer to C++0x's proposed new features?
  • What other cool features are in the plans for D 2.0?
  • I suggested a great feature. Why was the suggestion ignored?
  • Why const and immutable?
  • Why the names const and immutable?
  • How exactly is immutable related to multicores?
  • Ok, I'm fine with immutable for safe data sharing among threads. But why do we need the uninformative const?
  • Why are immutable strings favored in D 2.0?
  • I want to contribute to D 2.0. How can I effect that?
  • Why doesn't the case range statement use the case X..Y: syntax?
  • What guarantees is shared supposed to provide?
  • What does shared have to do with synchronization?
  • What does shared have to do with memory barriers?
  • What are the semantics of casting FROM unshared TO shared?
  • What are the semantics of casting FROM shared TO unshared?

General D FAQ

  • The D wiki FAQ page with many more questions answered
  • What does D have that C++ doesn't?
  • Why the name D?
  • Where 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?
  • Can't a sufficiently smart compiler figure out that a function is pure automatically?

Why doesn't the case range statement use the case X..Y: syntax?

See the case range statement.

The usages of .. would then be:

  1. case X..Y:
  2. foreach(e; X..Y)
  3. array[X..Y]
Case (1) has a VERY DIFFERENT meaning from (2) and (3). (1) is inclusive of Y, and (2) and (3) are exclusive of Y. Having a very different meaning means it should have a distinctly different syntax.

What guarantees is shared supposed to provide?

Shared means that multiple threads can access the data. The guarantee is that if it is not shared, and not immutable, that only the current thread can see it.

What does shared have to do with synchronization?

Only shared data can be synchronized. It makes no sense to synchronize thread local data.

What does shared have to do with memory barriers?

Reading/writing shared data emits memory barriers to ensure sequential consistency (not implemented).

What are the semantics of casting FROM unshared TO shared?

Make sure there are no other unshared references to that same data.

What are the semantics of casting FROM shared TO unshared?

Make sure there are no other shared references to that same data.

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.

Is there a linux port of D?

Yes, the D compiler includes a linux version.

Is there a GNU version of D?

Yes, gdc - 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?

D 2.0 does have a limited interface to C++ code.

Here are some reasons why it isn't a full interface:

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 overloads based on const and immutable.
  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++ does not distinguish between a class and a struct object.
  18. The vtbl[] location and layout is different between C++ and D.
  19. The way RTTI is done is completely different. C++ has no classinfo.
  20. D does not have two phase lookup, nor does it have Koenig (ADL) lookup.
  21. C++ relates classes with the 'friend' system, D uses packages and modules.
  22. C++ class design tends to revolve around explicit memory allocation issues, D's do not.
  23. D's template system is very different.
  24. C++ has 'exception specifications'.
  25. C++ has global operator overloading.
  26. C++ name mangling depends on const and volatile being type modifiers. D name mangling depends on const and immutable being type modifiers. D's const is also transitive, unlike C++. One cannot have a const pointer to mutable in D.

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.

Can't a sufficiently smart compiler figure out that a function is pure automatically?

The problems with the sufficently smart compiler argument are:

  1. most functions call other functions, which call other functions, until one of them calls a library routine whose source is not available to the compiler. So it will have to assume it is not pure. With a pure function attribute, external library functions that are pure can be marked as pure, and then the analysis can work for enough cases to be useful.
  2. Since virtual functions (and by extension delegates and function pointers) can be extended by the user at times the compiler won't see it, they have to be assumed to be impure.
  3. If the programmer intends for a particular function to be pure and the compiler detects it is not, this may go unnoticed by the programmer. Even worse, if the programmer does notice it, it may be arbitrarily difficult to determine why the compiler thinks it is impure - is it a programming mistake or a compiler bug?

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


const(FAQ)

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

const(FAQ)

D's const system is unique, and so there are a lot of questions about it.

  • Why does D have const?
  • What principles drove the D const design?
  • What is transitive const?
  • What is head const?
  • What is tail const?
  • What is logical const?
  • Why not use readonly to mean read only view?
  • Why did Java reject const?
  • How does const differ in C++?
  • Why are strings immutable?
  • Why aren't function parameters const by default?
  • Are static class members covered by transitive const?
  • What is immutable good for?

Why does D have const?

People often express frustration with const and immutable in D 2.0 and wonder if it is worth it.

  1. It makes function interfaces more self-documenting. Without transitive const, for all pointer/reference parameters one must rely on the documentation (which is always missing, out of date, or wrong). Note that without transitivity, C++ const is nearly useless for such self-documentation, which is why C++ programmers tend to rely on convention instead.
  2. It makes for interfaces that can be relied upon, which becomes increasingly important the more people that are involved with the code. In other words, it scales very well. People who are involved with projects with large teams of programmers say that lack of const makes their lives difficult because they cannot rely on the compiler to enforce convention. The larger the team, the worse it gets. Managing APIs is critical to a large project - it's why BASIC doesn't scale (for an extreme example).
  3. Const transitivity makes for some interesting optimization opportunities. The value of this has not been explored or exploited.
  4. Here's the biggie. Points 1..3 are insignificant in comparison. The future of programming will be multicore, multithreaded. Languages that make it easy to program them will supplant languages that don't. Transitive const is key to bringing D into this paradigm. The surge in use of Haskell and Erlang is evidence of this coming trend (the killer feature of those languages is they make it easy to do multiprogramming). C++ cannot be retrofitted to supporting multiprogramming in a manner that makes it accessible. D isn't there yet, but it will be, and transitive const will be absolutely fundamental to making it work.

Of course, for writing single-threaded one man programs of fairly modest size, const is not particularly useful. And in D const can be effectively ignored by just not using it, or by using D 1.0. The only place const is imposed is with the immutable string type.

What principles drove the D const design?

  1. It will be mathematically sound. That means there are no legal escapes from it.
  2. Any type can be wrapped in a struct and the resulting struct can still exhibit the same const behavior - in other words, no magic behavior for certain types.
  3. Const behavior will be transitive.
  4. Const behavior for type T will be equivalent for all types T.

What is transitive const?

Transitive const means that once const is applied to a type, it applies recursively to every sub-component of that type. Hence:

const(int*)** p;
p += 1;   // ok, p is mutable
*p += 1;  // ok, *p is mutable
**p += 1; // error, **p is const
***p += 1; // error, ***p is const

With transitivity, there is no way to have a const pointer to mutable int.

C++ const is not transitive.

What is head const?

Head const is where the const applies only to the component of the type adjacent to the const. For example:

headconst(int**) p;

would be read as p being a: const pointer to mutable pointer to mutable int. D does not have head const (the headconst is there just for illustrative purposes), but C++ const is a head const system.

What is tail const?

Tail const is the complement of head const - everything reachable from the const type is also const except for the top level. For example:

tailconst(int**) p;

would be read as p being a: mutable pointer to const pointer to const int. Head const combined with tail const yields transitive const. D doesn't have tailconst (the keyword is there just for illustrative purposes) as a distinct type constructor.

What is logical const?

Logical const refers to data that appears to be constant to an observer, but is not actually const. An example would be an object that does lazy evaluation:

struct Foo {
    mutable int len;
    mutable bool len_done;
    const char* str;
    int length()
    {   if (!len_done)
        {   len = strlen(str);
        len_done = true;
        }
    return len;
    }
    this(char* str) { this.str = str; }
}
const Foo f = Foo("hello");
bar(f.length);

The example evaluates f.len only if it is needed. Foo is logically const, because to the observer of the object its return values never change after construction. The mutable qualifier says that even if an instance of Foo is const, those fields can still change. While C++ supports the notion of logical const, D does not, and D does not have a mutable qualifier.

The problem with logical const is that const is no longer transitive. Not being transitive means there is the potential for threading race conditions, and there is no way to determine if an opaque const type has mutable members or not.

Reference: mutable: bitwise vs. logical const

Why not use readonly to mean read only view?

Readonly has a well established meaning in software to mean ROM, or Read Only Memory that can never be changed. For computers with hardware protection for memory pages, readonly also means that the memory contents cannot be altered. Using readonly in D to mean a read only view of memory that could be altered by another alias or thread runs counter to this.

Why did Java reject const?

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070

How does const differ in C++?

C++ has a const system that is closer to D's than any other language, but it still has huge differences:

  1. const is not transitive
  2. no immutables
  3. const objects can have mutable members
  4. const can be legally cast away and the data modified
  5. const T and T are not always distinct types

Why are strings immutable?

Immutable Strings

Why aren't function parameters const by default?

Since most (nearly all?) function parameters will not be modified, it would seem to make sense to make them all const by default, and one would have to specifically mark as mutable those that would be changed. The problems with this are:

  1. It would be a huge break from past D practice, and practice in C, C++, Java, C#, etc.
  2. It would require a new keyword, say mutable.
  3. And worst, it would make declarations inconsistent:
    void foo(int* p) {
   int* q;
   ...
}
    p points to const, and q points to mutable. This kind of inconsistency leads to all sorts of mistakes. It also makes it very hard to write generic code that deals with types.

Using in can mitigate the ugliness of having to annotate with const:

void str_replace(in char[] haystack, in char[] needle);

Are static class members covered by transitive const?

A static class member is part of the global state of a program, not part of the state of an object. Thus, a class having a mutable static member does not violate the transitive constness of an object of that class.

What is immutable good for?

Immutable data, once initialized, is never changed. This has many uses:

  • Access to immutable data need not be synchronized when multiple threads read it.
  • Data races, tearing, sequential consistency, and cache consistency are all non-issues when working with immutable data.
  • Pure functions can only accept immutable parameters.
  • When doing a deep copy of a data structure, the immutable portions need not be copied.
  • Invariance allows a large chunk of data to be treated as a value type even if it is passed around by reference (strings are the most common case of this).
  • Immutable type provides more self-documenting information to the programmer.
  • Immutable data can be placed in hardware protected read-only memory, or even in ROMs.
  • If immutable data does change, it is a sure sign of a memory corruption bug, and it is possible to automatically check for such data integrity.
  • Immutable types provide for many program optimization opportunities.

const acts as a bridge between the mutable and immutable worlds, so a single function can be used to accept both types of arguments.

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


The D Style

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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();
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.

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


Word Count

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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 = 0;
            buf ~= 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;
}

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


Future Directions

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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.

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


Change Log

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Sun Dec 19 22:08:35 2010

D Change Log

Under Construction

  1. 64 bit support for Linux
  2. Shared libraries for Linux
Version D 2.051 Dec 14, 2010

New/Changed Features

  • Added std.mathspecial, containing mathematical Special Functions
  • std.base64: Replaced. Boost License, Performance improvement, Range support. Function signature changed from 'encode' to 'Base64.encode'
  • std.math: D implementation of pow. Almost all std.math functions are now @safe pure nothrow. tgamma, lgamma, erf, erfc have been moved to std.mathspecial
  • std.exception: Added pure and nothrow to assumeUnique
  • std.utf: Removed UtfError class and toUTF* shortcut functions for validation. Added pure, nothrow, @safe and @trusted attributes. count function supports dchar
  • Both druntime and phobos now build successfully with dmd -m64. Still somewhat behind dmd1, very little executes correctly still.

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 2080: ICE(mangle.c) alias corrupts type inference of static variables
  • 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 2751: const/invariant/immutable static arrays: const(T)[N] and const(T[N]) are the same, but DMD treats them as different
  • Bugzilla 2954: [tdpl] Appalling bug in associative arrays (D2 only)
  • Bugzilla 2994: Incomplete "Predefined Versions" documentation
  • Bugzilla 3020: No description is given why function may not be nothrow
  • 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 3864: Dyn array allocations can be allowed in nothrow functions
  • Bugzilla 4059: Incorrect C++ name mangling
  • Bugzilla 4217: Function overloads are not distinguished when instantiating templates
  • Bugzilla 4254: ICE(mtype.c): function with const inout parameter
  • Bugzilla 4297: Nothrow functions cannot use constant dynamic array
  • Bugzilla 4384: Cyclic dependency check for modules is broken
  • Bugzilla 4434: ICE(mtype.c, 887) alias with const, shared, or immutable
  • Bugzilla 4445: roundTo!ubyte(255.0) throws
  • Bugzilla 4529: Segfault(typinf.c) involving typeid(typeof(functionName))
  • Bugzilla 4638: Regression: new writeln does not recognize "wstring toString"
  • Bugzilla 4728: Segfault(toctype.c) by protected/private constructor in an other module
  • Bugzilla 4781: Segfault(mtype.c) with forward referenced typeof and .init
  • Bugzilla 4864: ICE(statement.c) Crash on invalid 'if statement' body inside mixin
  • Bugzilla 4915: auto return type escapes function purity
  • Bugzilla 5020: Forward implicit bool conversions to alias this
  • Bugzilla 5053: Better error message for cyclic dependencies.
  • Bugzilla 5054: Splitter example doesn't work
  • Bugzilla 5094: No implicit conversion with "alias property this"
  • Bugzilla 5107: Const-shared classes/structs not typed as shared
  • 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 5131: Segfault(expression.c) opAssign and associative arrays (AA) are broken for types != this
  • Bugzilla 5133: dmd fails to build rdmd (problem with startsWith)
  • Bugzilla 5145: Regression(2.050, 1.065) override error with forward ref of superclass
  • Bugzilla 5148: Incorrect C++ mangling of multiple const char* parameters
  • Bugzilla 5154: Class Range does not work in writeln
  • Bugzilla 5159: Segfault(interpret.c): calling a static function pointer variable in CTFE
  • Bugzilla 5163: meaningless error message with front() applied to void[].
  • 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 5191: Combination of pure and nothrow result in a function that does nothing
  • Bugzilla 5194: ddoc does not show modifiers on constructors such as pure or nothrow
  • Bugzilla 5195: Forward references ignore const
  • Bugzilla 5214: Compiler crash with array of empty {}
  • Bugzilla 5218: Can't implicitly convert from "abc"w to wchar[3]
  • Bugzilla 5220: Make std.conv.ConvError an Exception instead of an Error; deprecated ConvError and ConvOverflowError with ConvException and ConvOverflowException. Note that any code depending on the fact that these exceptions were Error gets broken.
  • 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 5247: std.utf.stride() should not return 0xFF
  • Bugzilla 5275: x86_64 related hidden function parameter mishandled
  • Bugzilla 5293: std.math: Error: shift by -48 is outside the range 0..32
  • Bugzilla 5294: -O optimization breaks for loop
  • Bugzilla 5321: std.math: assumes X86 or X86_64 on FPU control word code
  • Bugzilla 5322: std.math: version(Sparc) should be SPARC
  • Bugzilla 5330: Druntime/Phobos: remove special treatment for GDC
  • Bugzilla 5331: mach format problem
  • Bugzilla 5340: isOutputRange!(Appender!string, int) must be false
  • Bugzilla 5353: clear function is calling the destructor twice
  • Version D 2.050
  • Version D 2.049
  • Version D 2.048
  • Version D 2.047
  • Version D 2.046
  • Version D 2.045
  • Version D 2.044
  • Version D 2.043
  • Version D 2.042
  • Version D 2.041
  • Version D 2.040
  • Version D 2.039
  • Version D 2.038
  • Version D 2.037
  • Version D 2.036
  • Version D 2.035
  • Version D 2.034
  • Version D 2.033
  • Version D 2.032
  • Version D 2.031
  • Version D 2.030
  • Version D 2.029
  • Version D 2.028
  • Version D 2.027
  • Version D 2.026
  • Version D 2.025
  • Version D 2.023
  • Version D 2.022
  • Version D 2.021
  • Version D 2.020
  • Version D 2.019
  • Version D 2.018
  • Version D 2.017
  • Version D 2.016
  • Version D 2.015
  • Version D 2.014
  • Version D 2.013
  • Version D 2.012
  • Version D 2.011
  • Version D 2.010
  • Version D 2.009
  • Version D 2.008
  • Version D 2.007
  • Version D 2.006
  • Version D 2.005
  • Version D 2.004
  • Version D 2.003
  • Version D 2.002
  • Version D 2.001
  • Version D 2.000
  • changelog for 1.0
  • Download latest D 2.0 alpha D compiler for Win32 and x86 linux
  • tech support
Version D 2.050 Oct 29, 2010

New/Changed Features

  • added talign() and argTypes() to TypeInfo
  • Upgrade zlib support to zlib 1.2.5
  • std.stdio: Added ByChunk. This struct is a InputRange like ByLine. File.byChunk returns ByChunk
  • std.traits: Most higher-order ranges now work with const/immutable arrays and other ranges with a natural tail const, and ranges w/ const/immutable elements.
  • Bugzilla 4888: Heavy reliance on Bug 3534 in Phobos range usage
  • Bugzilla 4987: C function pointer syntax needs to be deprecated
  • std.typecons: Several improvements to the Tuple struct template:
    • Tuple members are now accessible with the syntax a[0], a[1] etc.
    • Eliminated an internal union. See Bugzilla 4421 and Bugzilla 4846.
    • Worked around Bugzilla 4424. Got opAssign back.
    • Made Tuple.slice!(from, to) to preserve field names if any.
    • Added isTuple!(T) template.
  • std.algorithm: changed filter() such that filter is curryable
  • std.algorithm: Added function balancedParens
  • std.typecons: Deprecated defineEnum
  • Added relaxed purity checking rules.

Bugs Fixed

  • Unlisted bug: std.exception.pointsTo() calls postblit on subobjects.
  • Unlisted bug: std.typetuple.staticMap!() doesn't work with empty/single tuples.
  • Unlisted bug: std.traits: Interfaces should have indirections, aliasing, etc.
  • Unlisted bug: std.socket: Race condition - gethostbyname and gethostbyaddr on Linux return static data. The call was synchronized, but using the data wasn't
  • Unlisted bug: signed long comparisons under OS X
  • Bugzilla 941: std.regexp fails to match when grouping certain sub-expressions
  • Bugzilla 1482: std.file docs are insufficient
  • Bugzilla 1635: DirEntry.isfile() and DirEntry.isdir() broken
  • Bugzilla 1733: parse() function does not handle all build-in types
  • Bugzilla 2073: Variant.coerce!() fails
  • Bugzilla 2142: getopt() incorrectly processes bundled command-line options
  • Bugzilla 2310: Inconsistent formatting of arrays in std.stdio.write() and std.conv.to!(string)()
  • Bugzilla 2424: std.functional binaryRevertArgs : "revert" should be "reverse"
  • Bugzilla 2451: Adding structs that use opAssign or postblit to an AA is broken
  • Bugzilla 2655: Allow alternation patterns in std.path.fnmatch
  • Bugzilla 2669: Variant does not have opApply or another iteration mechanism
  • Bugzilla 2718: Inconsistent string parameters in Phobos functions
  • Bugzilla 2838: std.file.rmdirRecurse fails
  • Bugzilla 2930: Problems in std.range documentation
  • Bugzilla 2943: Struct copying in presence of alias member this only copies alias this member
  • Bugzilla 2965: std.date: timezone not initialized
  • Bugzilla 3157: [patch] Pipes should be closed with pclose
  • Bugzilla 3318: [PATCH]Rebindable.get is not accessible
  • Bugzilla 3570: mkdirRecurse throws exception on trailing empty directory.
  • 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 4344: Sockets with multiple threads report missing/failed WSAStartup
  • Bugzilla 4398: dmd always uses Windows name mangling for _d_throw
  • Bugzilla 4439: The declaration of the in6addr_* in druntime is wrong.
  • Bugzilla 4465: ICE(symbol.c): immutable type inference with ^^2
  • Bugzilla 4524: Regression(2.026) Bus error with nested struct
  • Bugzilla 4623: Non-integer type allowed as static array size
  • Bugzilla 4634: typo in levenshteinDistanceAndPath documentation
  • Bugzilla 4641: Associative arrays of structs with alias this broken.
  • Bugzilla 4742: int % BigInt should work.
  • Bugzilla 4775: No substitution on writef("%%%s", "hi").
  • Bugzilla 4825: Regression(1.057, 2.040) "Error: non-constant expression" with -inline
  • Bugzilla 4866: Static-to-dynamic converted manifest constant array gets non-converted type in static/constraint if
  • Bugzilla 4869: auto return + inheritance + modules = compiler crashes(toctype.c)
  • Bugzilla 4873: Assertion failure: '0' on line 1483 in file 'expression.c'
  • Bugzilla 4882: std.traits hasUnsharedAliasing does not work for function type.
  • Bugzilla 4897: CodeView: No locals or parameters are shown when debugging, because of missing function info
  • Bugzilla 4890: GC.collect() deadlocks multithreaded program.
  • Bugzilla 4925: [ICE] segfault with module-scope assert(0)
  • Bugzilla 4926: ICE: PREC_zero assertion failure due to unset precedence
  • Bugzilla 4938: Regression(2.047) dmd segfault when compiling
  • Bugzilla 4941: Built-in tuple slice boundaries are not CTFE'd
  • Bugzilla 4949: ICE on invalid static if using value of 'this'
  • Bugzilla 4951: InternetAddress fails to resolve host when multithreading.
  • Bugzilla 4959: std.conv.parse error "no digits seen" on string starting with zero.
  • Bugzilla 4992: ICE(glue.c) or segfault: using int[new]
  • Bugzilla 5003: regex(replace with delegate) sample doesn't work.
  • Bugzilla 5026: ICE(expression.c) Incomplete mixin expression + char[] to char assignment
  • Bugzilla 5049: std.algortihm.bringToFront() returns wrong value.
  • Bugzilla 5052: take!(Take!R) should return Take!R, not Take!(Take!R).
  • Bugzilla 5071: passing value by ref to a function with an inner dynamic closure results in a wrong code
Version D 2.049 Sep 13, 2010

New/Changed Features

  • std.algorithm: reduce now works with non-range-based iteration, such as opApply.
  • std.numeric: Added FFT.
  • std.path: Changed sep, altsep etc. to manifest constants (enum).
  • std.process: Added environment, an AA-like interface for environment variables.
  • std.range: Iota, Stride, Transversal, FrontTransveral now support slicing where possible.
  • std.range: Added support for moveFront() and assignable elements in several higher-order ranges.
  • std.range: Added Lockstep, hasLvalueElements.
  • std.range: Added virtual function-based wrappers (InputRangeObject, OutputRangeObject) for when a binary interface to a range is required.
  • std.typecons: Added convenience functions for Rebindable.
  • std.traits: Added isAssignable, isIterable, ForeachType, isSafe, isUnsafe, EnumMembers.
  • std.traits: hasLocalAliasing, hasLocalObjects and hasLocalRawAliasing are now hasUnsharedAliasing, hasUnsharedObjects and hasUnsharedRawAliasing. Aliases to the old names are included for now for backwards compatibility.
  • std.typetuple: Added anySatisfy.
  • std.array: Modified Appender's interface to fix memory issues. Note that appending via ~= and using appender on the same array will not interleave anymore.
  • Bugzilla 2477: Trailing comma in array literal sometimes accepted, sometimes not

Bugs Fixed

  • Andrej Mitrovic updated the samples/d code
  • Unlisted Bug: std.math.pow doesn't work on immutable numbers.
  • Unlisted Bug: std.math.pow floating point overload expects both arguments to be exact same type.
  • Unlisted Bug: std.path.join("", "foo") returns "/foo" instead of "foo" on Posix.
  • Unlisted Bug: std.range.iota() random access primitives inconsistent after popFront on floating point version
  • Unlisted Bug: std.algorithm.findAdjacent() [...]
  • 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 2903: Splitter should be bi-dir if the input range is bi-dir.
  • Bugzilla 2951: std.random.dice() should be templated on proportions.
  • Bugzilla 2958: std.getopt RangeError on missing arg
  • Bugzilla 3046: Segfault with C++ static variable (Linux only)
  • Bugzilla 3123: std.algorithm.zip fails on 'lazy' ranges
  • Bugzilla 3294: forward reference to inferred return type of function call
  • Bugzilla 3312: std.string.count should use const(char)[], not immutable.
  • Bugzilla 3348: Documentation for many std.process functions has disappeared
  • Bugzilla 3361: code in std.zlib concatenates void[] arrays
  • 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 3877: std.range.chain do not manage infinite ranges correctly
  • Bugzilla 3894: std.range.Stride!R requires R.front() and R.back() to return by reference
  • Bugzilla 3935: opBinary is instantiated with "="
  • Bugzilla 3946: schwartzSort - SwapStrategy always unstable
  • Bugzilla 3996: Regression(2.041) ICE(glue.c) Passing struct as AA template parameter (Algebraic with struct)
  • 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 4177: __ctfe can't be used in pure functions
  • Bugzilla 4278: allow inlining of super calls (undo limitations of bug3500's fix)
  • Bugzilla 4291: Pure functions cannot access mixed in variables
  • Bugzilla 4292: CommonType fails for singular alias value.
  • Bugzilla 4302: Regression(2.046, 1.061): compiler errors using startsWith in CTFE
  • Bugzilla 4345: std.range.take!string: "Nonsensical finite range with slicing but no length".
  • Bugzilla 4346: More flexible std.array.array.
  • Bugzilla 4363: Some phobos ranges are not forward ranges (but should be).
  • Bugzilla 4381: Length attribute for std.typecons.Tuple.
  • Bugzilla 4387: std.range.Cycle assumes lvalue elements.
  • Bugzilla 4388: std.range.Radial assumes lvalue elements.
  • Bugzilla 4402: std.range.Zip doesn't work w/ non-lvalue ranges.
  • Bugzilla 4403: std.range.FrontTransversal assumes lvalue elements.
  • Bugzilla 4404: std.range.Transversal assumes lvalue elements.
  • Bugzilla 4408: Ambiguity when using std.algorithm.splitter with generic ranges.
  • Bugzilla 4430: Regression(2.037) erroneous matching on specialized template function
  • Bugzilla 4455: Taking the sqrt of an integer shouldn't require an explicit cast.
  • Bugzilla 4464: std.range.take does not always return Take!R.
  • Bugzilla 4518: to!string(enum w/invalid value) produces a somewhat unhelpful error
  • Bugzilla 4564: ICE on undefined variable in foreach over 0 .. undef
  • Bugzilla 4603: array(iota(1, 0)) error.
  • Bugzilla 4643: Shared values are unwritable.
  • 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 4681: Appender access violation
  • Bugzilla 4691: Incorrect comparison of double and long
  • Bugzilla 4700: to!float("0") fails
  • Bugzilla 4721: compilation slow when compiling unittests on dcollections
  • Bugzilla 4748: Shadowing declaration error in std.string.tolower
  • 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 4789: std.algorithm.sort bug
  • Bugzilla 4810: dotProduct problem with ints
  • Bugzilla 4826: Regression(2.041) "cannot create associative array" and compiler crash
  • Bugzilla 4828: ICE w/ non-boolean dot expression sth.template_instance in static if
  • Bugzilla 4834: Implicit sharing via delegates in std.concurrency
Version D 2.048 Aug 8, 2010

New/Changed Features

  • std.complex: New Complex.toString() syntax.
  • std.string: icmp() now works with all built-in string types.
  • Bugzilla 4077: Bugs caused by bitwise operator precedence
  • Bugzilla 4080: Patch for building dynamic libraries on Mac OS X

Bugs Fixed

  • Unlisted Bug: std.algorithm.filter not a forward range
  • Unlisted Bug: std.algorithm.Uniq requires a bidirectional range
  • Unlisted Bug: std.algorithm.Uniq missing a save() function
  • Unlisted Bug: std.algorithm.Group missing a save() function
  • Unlisted Bug: std.traits.isAssociativeArray reports true for structs w/ keys, values properties
  • Unlisted Bug: gc_query returns 0 for attr when called on interior pointers
  • D/112964: capacity can return a value < length
  • Bugzilla 978: std.utf's toUTF* functions accept some invalid and reject some valid UTF
  • Bugzilla 996: Error in doc on implicit conversion between pointer and array
  • Bugzilla 1418: tupleof bug on nested classes
  • Bugzilla 1678: ref with varargs generates invalid code
  • Bugzilla 2275: std.utf.toUTF16z() should return const(wchar)*
  • Bugzilla 2627: std.traits.hasAliasing reports true for static arrays
  • Bugzilla 2872: Length, opIndex for Map
  • Bugzilla 2931: Initialization struct with array from another struct
  • Bugzilla 3202: std.math.pow cause dead loop
  • Bugzilla 3326: $ in delegate literal causes Access Violation
  • Bugzilla 3355: std.string.cmp works incorrectly for mixed-type and different-length strings
  • Bugzilla 3386: to!bool(string) is not implemented
  • Bugzilla 3436: std.functional.compose with only one function
  • Bugzilla 3439: std.range.Sequence.opIndex not consistent after calling popFront().
  • Bugzilla 3447: std.file uses unconventional file permissions
  • Bugzilla 3528: FreeBSD patches for druntime.
  • 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 3604: extern(C) callable function with array parameters broken
  • Bugzilla 3679: Regression(2.031) template forward reference regression
  • Bugzilla 3706: delegates of interfaces with multiple inheritance fail
  • Bugzilla 3716: Regression (2.037) with multi dimensional array literals
  • Bugzilla 3782: The POSIX sys/un.h header
  • Bugzilla 3853: core.sys.posix.stdio.pclose is missing
  • Bugzilla 3872: std.algorithm.filter could become bidirectional if its input range is bidir
  • Bugzilla 3874: std.range.stride assumes a bidirectional input range
  • Bugzilla 3917: opEquals for Ojbect could be more efficient
  • Bugzilla 3937: os.path.dirname fails on absolute path
  • Bugzilla 3961: Error with to!(somestruct)
  • Bugzilla 3983: Regression(2.037): struct with == can't be member of struct with template opEquals
  • Bugzilla 4109: (reopened) writeln doesn't work with empty static array
  • Bugzilla 4171: std.random.uniform does not work for a range of characters
  • 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 4260: windows & basename
  • Bugzilla 4267: forward reference error when 2-fold aliasing a template instance
  • Bugzilla 4303: __traits(compiles) returns wrong result when used recursively
  • Bugzilla 4305: Take, Chain on top of ranges w/o moveFront()
  • Bugzilla 4307: spawn()'ed thread doesn't terminate
  • Bugzilla 4314: Regression(1.062): Expression array1 && array2 doesn't compile
  • Bugzilla 4327: std.container.Array.Range.~this() tries to call free(T[])
  • Bugzilla 4339: Struct destructor + invariant + struct parameter = horrific error message
  • Bugzilla 4356: Copy constructor not called under extremely mysterious circumstances
  • Bugzilla 4362: std.range.repeat and cycle do not have a .save() method
  • Bugzilla 4363: std.algorithm.Until is not a forward range
  • Bugzilla 4369: Multiple bugs in GC minimize()
  • Bugzilla 4370: POSIX monitor attribute not being used
  • Bugzilla 4396: mkdir race prevents concurrent compiling with DMD using make -j
  • Bugzilla 4400: D2 GC doesn't allocate with 16 bytes alignment
  • Bugzilla 4406: Typo (bug) in std.concurrency
  • Bugzilla 4412: Array capacity growth spikey and the ratio approaches 1.0
  • Bugzilla 4443: Optimizer produces wrong code for || or && with struct arrays
  • Bugzilla 4452: Incorrect result of BigInt ^^ long
  • Bugzilla 4470: Problems with std.bigint mod and divide
  • 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 4516: Regression(2.040): forward declaration of enum not supported
  • Bugzilla 4551: D2 Language Docs: http://www.digitalmars.com/d/2.0/arrays.html
  • Bugzilla 4569: extern(c++) doesn't understand const types, produces bad mangled symbol
  • Bugzilla 4570: ElementType!(void[]) shows error message
  • Bugzilla 4578: Regression(2.047,1.062): ICE(cgcod.c): var+arr[]
  • Bugzilla 4590: Spec incorrectly describes array appending and memory stomping
Version D 2.047 Jun 11, 2010

New/Changed Features

  • Changed "op=" to just "op" for template argument to opOpAssign
  • std.algorithm: Added save() to forward ranges; added split() using only one element as separator; added indexOf; fixed unlisted bug in startsWith and endsWith; added skipOver(); added canFind().
  • std.array: Added implementation of save() for T[]s.
  • std.concurrency: Eliminated spurious unittest stdout messages.
  • std.container: Added.
  • std.conv: Added file and line information to conversion errors; added brackets '[' and ']' around arrays and associative arrays as defaults; added emplace() for non-class types.
  • std.file: Replaced exception upon out-of-memory error with assert(0).
  • std.functional: toDelegate now accepts callable(function pointers, delegates and objects implement opCall)
  • std.path: Made basename() generic in string type.
  • std.range: Added the existence of the property save as a condition for isForwardRange; added save to the range defined within; replaced a couple of awkward front() implementations; defined module-level moveFront() and range member moveFront() where appropriate; added @property maxLength to Take; arranged things such that take() for slice-able ranges returns the same type as the slice; eliminated SListRange; defined iota() with one argument; moved BinaryHeap within.
  • std.regex: Qualified indexOf with std.algorithm.
  • std.regexp: Qualified indexOf with std.algorithm.
  • std.stdio: Added an error message to enforce() in rawRead().
  • std.string: Improved indexOf(), tolower(), splitter(), chomp().
  • std.traits: Added templates to get compile-time information about functions.
  • std.typecons: Added AutoImplement.
  • std.utf: Eliminated decodeFront() and decodeBack() - they aren't needed since strings are bidirectional ranges.
  • Bugzilla 2008: Poor optimization of functions with ref parameters
  • Bugzilla 3793: Functions with static arrays as arguments are not inlined
  • 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 2738: Rebindable should work for interfaces.
  • Bugzilla 2835: std.socket.TcpSocket doesn't actually connect
  • Bugzilla 2881: x.stringof returns typeof(x).stringof when x is an enum
  • Bugzilla 3064: Invalid array operation accepted, generates bad code
  • Bugzilla 3088: std.xml.check() fails on xml comments
  • Bugzilla 3139: compiler dies "Error: out of memory" with case range
  • Bugzilla 3200: std.xml doesn't follow spec for Tag.text
  • Bugzilla 3323: Segfault or ICE(e2ir.c) using struct with destructor almost anywhere
  • Bugzilla 3398: Attributes inside a union screws data alignment
  • Bugzilla 3465: isIdeographic can be wrong in std.xml
  • Major improvements to CustomFloat, fixing Bugzilla 3520: std.numeric.CustomFloat horribly broken
  • Bugzilla 3538: Default value of alias template parameter is instantiated only once.
  • 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 3604: extern(C) callable function with array parameters broken
  • Bugzilla 3651: mangleof broken for enums
  • Bugzilla 3653: Problem sorting array of Rebindable
  • Bugzilla 3658: Crashing on vector operations (Mac only)
  • Bugzilla 3662: Wrong compile error within struct constructor and C-style initializer
  • Bugzilla 3667: Regression(D2 only): broken out(result) in contracts
  • Bugzilla 3786: bug in std.string.removechars
  • Bugzilla 3854: Error on static initialization of arrays with trailing comma.
  • Bugzilla 3873: std.range.repeat should have popBack defined
  • Bugzilla 3876: std.range.Take back/popBack methods don't work correctly
  • Bugzilla 3880: std.regex functions with const/immutable Regex object
  • 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 4056: Template instantiation with bare parameter not documented
  • Bugzilla 4073: core.cpuid crashes
  • Bugzilla 4078: [CTFE] Failed return of dynamic array item
  • Bugzilla 4084: Ignored missing main() closing bracket
  • Bugzilla 4109: writeln doesn't work with empty static array
  • 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 4188: std.file.remove throws Exception on success
  • Bugzilla 4193: Regression 2.046, ICE(expression.c): initialising class member with const forward reference
  • Bugzilla 4202: Changset 1517 doesn't compile
  • Bugzilla 4207: std.cover.setDestDir does not work.
  • Bugzilla 4208: druntime should not depend on Phobos
  • Bugzilla 4212: DWARF: void arrays cause gdb errors
  • Bugzilla 4213: Strange behaviour with static void[] arrays
  • Bugzilla 4219: hasAliasing does not care about immutable
  • Bugzilla 4220: I cannot apply @safe to intrinsic operation(eg: std.math.sqrt)
  • Bugzilla 4228: std.array.replace contains 2 bugs
  • Bugzilla 4230: version(unittest)
  • Bugzilla 4231: Solitary opUnary Postincrement and Postdecrement user defined operators are broken.
  • Bugzilla 4242: ICE(module.c): importing a module with same name as package
  • Bugzilla 4249: std.regex fails to compile with debug=regex
  • 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 4262: Header generation omits 'enum' for enum declarations
  • Bugzilla 4263: Header generation omits '@system' attribute
  • Bugzilla 4270: Missing line number in 'can only catch class objects' error message
  • Bugzilla 4300: BigInt * int doesn't work well
Version D 2.046 May 10, 2010

New/Changed Features

  • Add hints for missing import declarations.
  • Speed up compilation.
  • All length methods in Phobos are now a @property.
  • Bugzilla 1001: print stack trace (in debug mode) when program die

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 3945: AssertExpression message should implicitly convert to const char[]
  • 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
  • Bugzilla 4116: object.di does not match object_.d
  • Bugzilla 4146: Unavailable: core.sys.posix.sys.wait.waitid()
  • Bugzilla 4184: associative array with certain key types results in corrupt values during iteration
Version D 2.045 May 4, 2010

New/Changed Features

Bugs Fixed

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

New/Changed Features

  • Improve spelling checking distance to 2.
  • Now all unittests are run, even if some fail
  • Many small improvements to error diagnostics and recovery

Bugs Fixed

  • Bugzilla 1079: gdb: Dwarf Error: Cannot find DIE at 0xb705 referenced from DIE at 0x250
  • Bugzilla 2437: ICE(tocsym.c, !needThis()) - default struct argument
  • Bugzilla 2935: ICE(out.c) using struct with constructor as function default argument
  • 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 3987: [gdb] Invalid DWARF output for function pointers
  • Bugzilla 3974: ICE(init.c): Static array initializer with more elements than destination array
  • 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 4072: Stack overflow on recursive template expansion inside contract
  • Bugzilla 4081: cannot compile the dmd on FreeBSD 8
  • 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
  • Bugzilla 4108: ICE(cod2.c): zero-length static array in function call
  • Bugzilla 4118: std.conv.to!SomeStruct("hello") crashes compiler
  • Bugzilla 4131: break does not work correctly with foreach and associative arrays
Version D 2.043 Apr 6, 2010

New/Changed Features

  • .init property for static arrays is now an array literal
  • Improved speed of associative arrays
  • std.bigint has been completely replaced with a faster implementation. Multiplication is now 5 times faster, division is 300 times faster, and squaring is 10 times faster. For large numbers (~5000 words), the speedup is 5 times larger than this.

Bugs Fixed

  • Fixed memory corruption problem with array appends
  • 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 3884: Segfault: defining a typedef with an invalid object.d
  • Bugzilla 3911: Associative array in CTFE crashes compiler
  • Bugzilla 3958: mixin(non-static method) crashes compiler
  • Bugzilla 3972: Regarding module with name different from its file name
  • Bugzilla 3984: Segfault(interpret.c): CTFE using struct constructor on a local static variable
  • Bugzilla 3986: Struct constructors bypass default initialization of member variables
  • 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 4023: std.math.hypot() returns infinity when either argument is zero
  • Bugzilla 4027: Closures in CTFE generate wrong code
  • Bugzilla 4029: CTFE: cannot invoke delegate returned from function
Version D 2.042 Mar 19, 2010

New/Changed Features

Bugs Fixed

  • Add base class destruction to clear() in object.d
  • Bugzilla 3842: ICE(expression.c) using pointer in CTFE
  • 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 3902: Definition of opCmp
  • Bugzilla 3912: pure static nested functions are not recognized as pure
  • 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 3930: AAs horribly broken
Version D 2.041 Mar 7, 2010

New/Changed Features

  • __traits allMembers and and derivedMembers now return a tuple of strings rather than an array of strings. Enclose __traits in [ ] to make array literal. This makes it possible for foreach statements to iterate at compile time over it.
  • Interface member functions can now have contracts.
  • Added new operator overloading regime.
  • 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
  • Mixin template definitions should be preceded with mixin
  • Add !in operator.
  • Associative array contents can now be compared for equality
  • Use of length inside of [ ] is now deprecated, use $ instead
  • Added toDelegate() to std.functional to convert function pointers to delegates.
  • Implemented attributes for constructors.
  • Implemented qualifiers for struct literals, like immutable(S)(1,2,3)
  • Array equality can now be done with differing array element types.
  • Add simple spell checking.
  • Bugzilla 3378: [tdpl] ++x should be an lvalue
  • string, wstring are now bidirectional (not random) ranges
  • std.algorithm: defined move with one argument; levenshtein distance generalized to with all forward ranges; take now has swapped arguments
  • std.array: empty for arrays is now a @property; front and back for a string and wstring automatically decodes the first/last character; popFront, popBack for string and wstring obey the UTF stride
  • std.conv: changed the default array formatting from "[a, b, c]" to "a b c"
  • std.range: swapped order of arguments in take
  • std.stdio: added readln template
  • std.variant: now works with statically-sized arrays and const data
  • std.traits: added isNarrowString
  • The default type for [1,2,3] is now int[] rather than int[3].

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 3453: Linking order affects proper execution (Mac OSX only)
  • Bugzilla 3491: typeof((string[string]).init) == AssociativeArray!(string, string), doesn't implicitly convert to string[string].
  • Bugzilla 3500: super behaves differently with -inline
  • Bugzilla 3558: Optimizer bug results in false if condition being taken
  • Bugzilla 3582: core.stdc.ctype functions are not pure
  • Bugzilla 3619: Thread crash on exit
  • Bugzilla 3637: Array append patch to prevent stomping and to enhance thread-local append performance
  • Bugzilla 3644: Wrong UCHAR_MAX value in module core.stdc.limits
  • Bugzilla 3670: Declarator grammar rule is broken
  • Bugzilla 3689: Grammar does not allow const(int)
  • Bugzilla 3692: ICE(mtype.c) with associative arrays when std.variant is imported
  • Bugzilla 3695: __EOF__ token not documented
  • Bugzilla 3697: StructTemplateDeclaration and others missing constraint in rule
  • 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 3763: std.stdio.readlnImpl absurdly inefficient and overflows stack
  • 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 3776: Wrong CHAR_MIN value in module core.stdc.limits
  • Bugzilla 3781: ICE(interpret.c): using no-argument C-style variadic function in CTFE
  • Bugzilla 3803: compiler segfaults
  • Bugzilla 3840: Jump to: section in the docs should be sorted
Version D 2.040 Jan 29, 2010

New/Changed Features

  • Clarification: function returns are not lvalues
  • Added shared static constructors/destructors, regular static constructors/destructors now deal with TLS
  • Add -map command line switch
  • Add @disable attribute
  • 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
  • added static/final function implementations to interfaces
  • added getOverloads, identifier, and isStaticFunction traits.
  • ModuleInfo changed from class to struct
  • Bugzilla 3556: version(CTFE)
  • Bugzilla 3728: getOverloads and identifier traits

Bugs Fixed

  • Added TLS support for OSX
  • Bugzilla 47: Internal error: cg87 3316
  • 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?
  • Bugzilla 2066: to!(string)(int) into CTFE-compatible
  • Bugzilla 3488: Segfault(expression.c): enum declared with struct static initializer
  • Bugzilla 3535: struct constructors don't work in CTFE
  • Bugzilla 3552: ICE(mtype.c): declaring a variable called 'AssociativeArray' then using an AA.
  • Partial fix for Bugzilla 3569, stops the stack overflow
  • Bugzilla 3600: template instantiation with empty tuple
  • Bugzilla 3660: Templates and shared functions don't mix
  • Bugzilla 3668: foreach over typedef'd array crashes dmd
  • Bugzilla 3671: x^^3 gives wrong result when x is a floating-point literal
  • Bugzilla 3674: forward reference error with multiple overloads with same name
  • Bugzilla 3675: Regression: Struct literals cannot be initialized with another struct literal
  • 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 3727: lots of "deffering SomeStructName" messages when compiling
  • Bugzilla 3734: [patch] src/traits.c does not compile with gcc (Ubuntu 4.4.1-4ubuntu8) 4.4.1
  • Bugzilla 3740: Regression: class with fwd reference of a nested struct breaks abstract
Version D 2.039 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 2.038 Dec 30, 2009

New/Changed Features

  • Added core.cpuid in Druntime
  • Bugzilla 3514: opApply should be the first-choice foreach iteration method.
  • Bugzilla 3577: Wrong precedence for opPow
  • Added auto ref functions
  • Added function template auto ref parameters
  • Added isRef, isOut and isLazy to __traits
  • Transporting return type from args to return type, see DIP2

Bugs Fixed

  • Bugzilla 45: Internal error: cgcod 1594
  • Bugzilla 46: Constant folding with long doubles
  • 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 3270: pure functions returning struct
  • Bugzilla 3443: Thread.thread_needLock() should be nothrow
  • Bugzilla 3455: Some Unicode characters not allowed in identifiers
  • Bugzilla 3458: int fsync(int) commented out in core.sys.posix.unistd
  • Bugzilla 3476: C-style initializer for structs must be disallowed for structs with a constructor
  • Bugzilla 3575: CTFE: member structs not initialized correctly
  • Bugzilla 3583: Unsigned right shift works the same as signed right shift.
  • 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 3596: Need alias for using std.algorithm.remove
  • 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 3621: implicit conversion to const rules need tightening
  • Bugzilla 3633: Optimizer causes access violation
  • Bugzilla 3641: alias shared T U does not work
  • Bugzilla 3645: manifest constant (enum) crashes dmd
  • Bugzilla 3647: non-function opDispatch crashes dmd
Version D 2.037 Dec 3, 2009

New/Changed Features

  • Conditional expressions ?: can now be modifiable lvalues.
  • The type inferred from an ArrayLiteral is now a dynamic array, not a static one.
  • Added support for op= for array.length
  • Array and associative array types are now determined by using ?: across all the elements, not just using the first one.
  • Array concatenation with elements now allows implicit conversion of the elements to the array element type.
  • No more comma operators allowed between [ ].
  • ClassInfo now merged into TypeInfo_Class.
  • Bugzilla 3379: [tdpl] Parameter names not visible in the if clause of a template
  • Bugzilla 3380: [tdpl] typeid(obj) should return the dynamic type of the object
  • Removed -safe command line switch, added -noboundscheck command line switch.
  • Bugzilla 3481: PATCH: opPow(), x ^^ y as a power operator
  • Added opDispatch
  • properties can only have 0 or 1 arguments
  • properties cannot be overloaded with non-properties
  • std.math: Added FloatControl, IeeeFlags for enabling floating-point exceptions.
  • std.math: Inverse trig functions are now pure nothrow.

Bugs Fixed

  • std.array: Fixed unlisted bug in array().
  • Bugzilla 111: appending a dchar to a char[]
  • Bugzilla 2664: OSX standard math functions are less accurate
  • Bugzilla 2802: VariantN.opCmp!(T) fails when T != VariantN
  • Bugzilla 2967: spec does not mention that inline asm is a valid "return" statement
  • Bugzilla 2977: std.random.unpredictableSeed() should use thread ID somewhere
  • Bugzilla 3115: >>> and >>>= generate wrong code
  • Bugzilla 3171: % not implemented correctly for floats
  • Bugzilla 3311: std.range.chain shouldn't have opIndexAssign if arguments aren't mutable
  • Bugzilla 3375: [tdpl] Ternary operator doesn't yield an lvalue
  • Bugzilla 3381: [tdpl] Incorrect assessment of overriding in triangular-shaped hierarchy
  • Bugzilla 3388: [tdpl] contracts should allow throw expressions
  • Bugzilla 3390: [tdpl] out(result) contract should not be able to rebind result
  • Bugzilla 3407: [tdpl] Compiling with -safe -release must keep all bound checks
  • Bugzilla 3433: [tdpl] Comparing structs for equality is not member-by-member
  • Bugzilla 3469: ICE(func.c): Regression. Calling non-template function as a template, from another module
  • Bugzilla 3478: "no effect in expression" error on return to void
  • Bugzilla 3494: Segfault(mtype.c) using typeof(return) inside an auto function
  • 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
  • Bugzilla 3551: nested struct => dmd adds a hidden pointer
  • Bugzilla 3553: ICE when a function argument defaults to __LINE__
Version D 2.036 Nov 5, 2009

New/Changed Features

  • Static arrays are now passed by value to functions rather than by reference
  • std.algorithm: Add hasLength requirement to topN; implemented topN for two non-adjacent ranges; added replaceTop function to BinaryHeap; changed BinaryHeap.top to return ref.
  • std.ctype: Add pure to isalnum, isalpha, iscntrl, isdigit, islower, ispunct, isspace, isxdigit, isgraph, isprint, isascii, toupper.
  • std.date: Implementation change and unittest for isLeapYear and daysInYear. Made both pure as well.
  • std.encoding: Added function count().
  • std.md5: Added explicit pass-by-ref for fixed-size buffers.
  • std.numeric: Added gcd.
  • std.random: Added static checks for the parameters of the linear congruential generator.
  • std.range: Reinstated some unittests; fixed Cycle to work with the new fixed-size arrays.
  • std.typecons: Added alias 'expand' for Tuple.field.
  • std:utf: Added count function and changed the encode function to take fixed-size array by reference.
  • Bugzilla 3446: Rename float.min to float.min_normal

Bugs Fixed

  • std.range: Fixed unlisted bug in Transposed.
  • 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 1117: ddoc generates corrupted docs if code examples contain attributes with colons
  • Bugzilla 1812: DDOC - Unicode identifiers are not correctly marked.
  • Bugzilla 2694: alias pure nothrow XXX; is not pure nothrow!
  • Bugzilla 2862: ICE(template.c) using type tuple as function argument
  • Bugzilla 3035: cannot have const/invariant out parameter of type shared
  • Bugzilla 3102: Incorrectly matching type as shared (two cases with is expressions)
  • Bugzilla 3269: pure functions silently become nothrow
  • Bugzilla 3292: ICE(todt.c) when using a named mixin with an initializer as template alias parameter
  • Bugzilla 3349: typeid(shared(T)) generates wrong value
  • Bugzilla 3367: Regression: struct initialization no longer supports ctor overloads
  • 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 3423: Destructor and postblit don't get copied to the header file when using -H
  • Bugzilla 3426: ICE(optimize.c): struct literal with cast, as function default parameter.
  • Bugzilla 3429: Core dump on passing template literal to member function.
  • Bugzilla 3432: ICE(e2ir.c): casting template expression
Version D 2.035 Oct 14, 2009

New/Changed Features

  • Use -X to generate JSON files.

Bugs Fixed

  • Fold in patch from Bugzilla 1170
  • Bugzilla 1534: Can't mix in a case statement.
  • Bugzilla 2423: Erroneous unreachable statement warning
  • Bugzilla 2826: failed assignment gives wrong line number
  • Bugzilla 3190: enum doesn't work as the increment in a for loop
  • Bugzilla 3316: Functions nested in a pure templated function cannot reference its local variables
  • Bugzilla 3352: RangeError in std.conv
  • Bugzilla 3385: `std.string.split` requires a mutable array
  • Bugzilla 3392: a cast of this to void in tango.core.Thread is not allowed
Version D 2.034 Oct 11, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 258: Undefined identifier error for circular import
  • 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 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 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 3042: Segfault on incorrect override
  • Bugzilla 3101: Stack overflow: declaring aggregate member twice with static if
  • Bugzilla 3119: Segfault(expression.c) template function overloads with function with same name in other module
  • 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 2.033 Oct 5, 2009

New/Changed Features

  • Phobos is now using the Boost 1.0 license
  • Compiler now detects some cases of illegal null dereferencing when compiled with -O
  • The result type of the typeid(type) is now the most derived TypeInfo class, rather than the TypeInfo base class
  • Bugzilla 2905: Faster +-*/ involving a floating-pointing literal
  • Improved performance of int-to-string conversion

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 1253: array initializers as expressions are not allowed in const arrays
  • 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 2970: std.path.join with version(Windows)
  • Bugzilla 2998: ICE(expression.c) with floating point enum
  • Bugzilla 3049: ICE(cod4.c) or segfault: Array operation on void[] array
  • Bugzilla 3059: Nonsensical complex op= should be illegal
  • Bugzilla 3132: std.string.split should be templated on mutable/const/immutable - closing again after the reopening on 2009-09-03 07:56:25 PDT
  • Bugzilla 3160: ICE(cgcod.c 1511-D1) or bad code-D2 returning string from void main
  • Bugzilla 3173: ICE(mtype.c) on wrong code (double to long to int conversion)
  • Bugzilla 3288: conv.d: using to with const int or long fails to compile.
  • Bugzilla 3300: std.string.toupper and tolower should be (const(char)[]), not string
  • Bugzilla 3304: Segfault using 'is' with a pointer enum.
  • Bugzilla 3305: Segfault(expression.c) with recursive struct template alias expressions
  • Bugzilla 3333: std.conv.to!(string, const int) error: cannot modify const
  • Bugzilla 3335: minor warning cleanups
  • Bugzilla 3336: ICE(glue.c) declaring AA with tuple key, only with -g
  • Bugzilla 3340: std.string.split(S1 s, S2 delim) still doesn't work for char[]
  • Bugzilla 3353: storage class of a member function is propagated to default arguments
  • (unlisted): std.algorithm: bug in reduce when passed const arguments
  • (unlisted): std.stdio: fixed documentation example
  • (unlisted): std.utf: fixed decodeFront and decodeBack
Version D 2.032 Sep 2, 2009

New/Changed Features

  • Improved exception message for assert(0) in Windows -release builds
  • 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
  • synchronized member functions now implicitly typed as shared.
  • std.algorithm: added minPos
  • std.format: added raw specifier for reading
  • added File.byChunk
  • std.algorithm: added more unittests and checks for user-based comparison passed to topN
  • std.math: replaced std.c with core.stdc; improved approxEqual to work with ranges, not only numbers or arrays
  • std.range: defined Take.popBack whenever sensible; improved iota to accept negative ranges and steps

Bugs Fixed

  • Bugzilla 601: statement.html - Formatting/markup errors in BNF
  • Bugzilla 1461: Local variable as template alias parameter breaks CTFE
  • Bugzilla 1600: Functions taking only one array cannot be called with property syntax
  • Bugzilla 1604: Non-final method on final struct is too restrictive (closed with "invalid" advise)
  • Bugzilla 1605: break in switch with goto breaks in ctfe
  • Bugzilla 1616: std/metastrings.d
  • Bugzilla 1940: Phobos buildscripts do not work on x86_64
  • Bugzilla 1948: CTFE fails when mutating a struct in an array
  • Bugzilla 1950: CTFE doesn't work correctly for structs passed by ref
  • Bugzilla 1969: ICE(cod1.c) using undefined operator with one const operand
  • Bugzilla 1972: Foreach range statement breaks CTFE
  • Bugzilla 2150: cannot get values from const variant
  • Bugzilla 2277: array ops and const arrays incompatible
  • Bugzilla 2398: writef("%x") for a pointer is always uppercase
  • Bugzilla 2560: ICE(cod4.c) on invoking method that takes ref const struct parameter
  • Bugzilla 2564: CTFE: the index in a tuple foreach is uninitialized (bogus error)
  • Bugzilla 2569: static arrays in CTFE functions don't compile
  • Bugzilla 2575: gdb can not show code
  • Bugzilla 2587: std.process.shell doesn't work for win32
  • Bugzilla 2604: DW_TAG_module and GDB
  • Bugzilla 2665: ICE(cod4.c) on certain const struct function return types
  • Bugzilla 2784: Interfaces should be able to require type definitions (closed with "invalid" advise)
  • Bugzilla 2785: Interfaces should be able to require non-member functions (closed with "invalid" advise)
  • Bugzilla 2786: Interfaces should be able to require constructors (closed with "invalid" advise)
  • Bugzilla 2882: std.random.MersenneTwisterEngine without no seed
  • Bugzilla 2925: Destructor not called
  • Bugzilla 2937: postblit not called for foreach arg over array of structs
  • Bugzilla 2940: null is null cannot be evaluated at compile time
  • Bugzilla 2976: rename retreatN to retreat
  • Bugzilla 2979: Xml tags with only attributes return as without attributes ElementParser.parse
  • Bugzilla 2980: compiler error when writefln( uint )
  • Bugzilla 2987: D2 phobos BigInt opMul doesn't work correctly
  • Bugzilla 2988: Chain needs opIndexAssign.
  • Bugzilla 2989: std.typetuple: add support for any static tuples
  • Bugzilla 2992: (closed with "later" advise)
  • Bugzilla 2996: std.typetuple: add support for any static tuples
  • Bugzilla 3000: iota should work with floats
  • Bugzilla 3017: doc errors in std.range (on behalf of Steven Schveighoffer)
  • Bugzilla 3025: uniform(float,float) pops first, uniform(int,int) pops last
  • Bugzilla 3037: Off-by-one error in Stride.length
  • Bugzilla 3039: -vtls compiler flag not listed in man file
  • Bugzilla 3058: [CTFE] Cannot return out of foreach range statement
  • Bugzilla 3074: std.conv.to!(string)(int.min)
  • Bugzilla 3077: 3077 crash exiting main() without result code
  • Bugzilla 3087: std.range.retro.opIndex out of range
  • Bugzilla 3098: std.algorithm.reduce example can not compile
  • Bugzilla 3100: ICE(cast.c) struct with members is shared
  • Bugzilla 3132: std.string.split should be templated on mutable/const/immutable
  • Bugzilla 3148: syntax error using invariant
  • Bugzilla 3153: win32.mak tries to copy phobos.lib, gcstub.obj to nonexistent folder lib
  • Bugzilla 3162: can't fully use compile-time floats as template parameters
  • Bugzilla 3165: What kind of integer division does D use?
  • Bugzilla 3166: "positive" -> "non-negative" in modulo operator description
  • Bugzilla 3169: Segfault(cast.c) dividing ulong by int
  • Bugzilla 3170: Forward reference of nested class fails if outer class is not plain
  • Bugzilla 3183: Spec of align attribute needs work
  • Bugzilla 3184: std.algorithm.until should work like "find"
  • Bugzilla 3185: osx is not a directory (complains cannot read std/c/osx/socket.d)
  • Bugzilla 3186: corrections for http://www.digitalmars.com/d/2.0/dmd-osx.html
  • Bugzilla 3189: `std.conv.to` : check for a custom `to` method in classes/structs
  • Bugzilla 3192: asm in a anonymous delegate crash the compiler
  • Bugzilla 3195: `std.conv` pureness (closed with "later" advise)
  • Bugzilla 3196: Segfault(mtype.c) after almost any error involving a delegate literal
  • Bugzilla 3197: Minor fixes and additions to std.traits
  • Bugzilla 3199: sort(chain(...)) doesn't work in some cases
  • Bugzilla 3205: CTFE: $ cannot be used in lvalues
  • Bugzilla 3212: Error message says "mutable"; should say "immutable"
  • Bugzilla 3217: std.functional.binaryFunImpl doesn't support UDT with string functions , therefore neither does many std.algorithm functions
  • Bugzilla 3218: Performance of std.xml.encode must be improved
  • Bugzilla 3219: Inaccurate std.conv.to!(numeric)(numeric) error messages
  • Bugzilla 3224: std.random documentation bugs
  • Bugzilla 3229: No return or assert(0) at end of function
  • Bugzilla 3236: Postblit called but no matching destructor
  • Bugzilla 3239: std.conv.roundTo does not accept const/immutable/shared
  • Bugzilla 3240: std.numeric.findRoot only works with real
  • Bugzilla 3242: splitter does not handle input range made of a unique separator correctly
  • Bugzilla 3245: Easy bug fix available for disabled unit test code in std.encoding
  • Bugzilla 3246: ICE(init.c) using indexed array initializer on local array
  • Bugzilla 3249: sort and setIntersection on array of struct or class
  • Bugzilla 3253: DMD crashes on function pointer struct member initialization with function literal
  • Bugzilla 3255: final switch broken with -w switch
  • Bugzilla 3257: Spec is unclear describing string switch case labels
  • Bugzilla 3260: "Error: undefined identifier backend" when compiling 'write' with 'wchar'
  • Bugzilla 3264: -O causes wrong "used before set" error when using enum.
  • Bugzilla 3281: ICE(cod1.c) append returned struct to array
  • Fixed bug processing spaces in dmd's directory
  • Fixed assert failure on line 4823 in expression.c
  • Fixed OSX compile error on samples/d/dhry.d
  • std.format: fixed unlisted bug in documentation
  • std.random: uniform does not work when passed immutable data
  • std.range: fixed unlisted bug in Take.back
  • unlisted: made entropy work on const/immutable arrays
Version D 2.031 July 6, 2009

New/Changed Features

  • Renamed root directory \dmd to \dmd2
  • Use of with symbols that shadow local symbols is no longer allowed
  • Added final switch statements
  • Added case range statements
  • Implicit integral conversions that could result in loss of significant bits are no longer allowed.
  • Warning on no return expr; is now an error.
  • Bugzilla 3080: dmd should output compilation errors to stderr, not stdout
  • Bugzilla 3122: [patch] Adding support for fast and reliable build tools to the frontend
  • std.algorithm: Made std.algorithm.swap faster by having it use memcpy; added std.algorithm.group, std.algorithm.until, std.algorithm.nWayUnion, std.algorithm.largestPartialIntersectionWeighted; added additional constraints to std.algorithm.equal; changed signature of std.algorithm.topNIndex and std.algorithm.topNCopy to use an enum parameter instead of a confusing bool.
  • std.array: added array function.
  • std.conv: added Shin Fujishiro's code for printing and parsing enumerated values.
  • std.ctype: made isupper and tolower pure.
  • std.date: changed signature of benchmark to return ulong[] instead of uint[].
  • std.demangle: changed it to use the snazzy switch statement with ranged labels.
  • std.random: added randomSample
  • std.string: deprecated std.string.find and std.string.find, replaced with std.string.indexOf; deprecated std.string.rfind and std.string.irfind, replaced with std.string.lastIndexOf; added flag CaseSensitive for indexOf and lastIndexOf; removed startsWith and endsWith because std.algorithm defines them; defined std.string.byDchar.
  • std.traits: added isSomeChar, isPointer.
  • std.typetuple: replaced indexOf with indexOfType, kept the old name as an alias that will be deprecated.
  • std.utf: improved error messages.

Bugs Fixed

  • Fix dmd crash on multicore Windows.
  • Fixed unlisted bug in std.algorithm.startsWith
  • Fixed unlisted bug in std.algorithm.topN
  • Fixed unlisted bug in std.algorithm.topNIndex (empty index made it crash)
  • Fixed unlisted bug in std.algorithm.setIntersection
  • Fixed unlisted bug in std.range.retro: retro'izing a range twice must return the original range
  • 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 1343: Various errors with static initialization of structs and arrays
  • Bugzilla 1358: ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF
  • 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 2399: ICE(cgcod.c) on casting function to delegate
  • 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 2865: RandomCover not random
  • Bugzilla 2875: ICE(cgcod.c) setting delegate = &Struct.func
  • Bugzilla 2884: ICE: Assert: 'template.c', line 3773, 'global.errors'
  • Bugzilla 2888: [PATCH] speedup for float * 2.0
  • Bugzilla 2900: Array appending slowed drastically since integration of druntime
  • 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 2974: Segfault(mtype.c) on auto function
  • Bugzilla 2981: Bad code generation for structs containing invariants
  • Bugzilla 2982: Assertion failure in function if() clause
  • 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 3071: nested func declaration parse problem
  • Bugzilla 3078: NaN reported as equal to zero
  • Bugzilla 3081: unaryFun can't be used to get element out of struct.
  • Bugzilla 3095: wc example for D2 doesn't compile
  • Bugzilla 3114: optlink failing on multicore machines
  • Bugzilla 3117: dmd crash by *1
  • Bugzilla 3121: recurrence does not generate the correct numbers
  • Bugzilla 3128: Internal error: ..\ztc\cod4.c 2737
  • Bugzilla 3130: Crashed with triple stars
Version D 2.030 May 11, 2009

New/Changed Features

  • added -vtls compiler switch
  • classic global storage now defaults to TLS (Thread Local Storage). This is a big change, see Migrating To Shared.
  • std.algorithm: added minPos. Improvements to Splitter suggested by Brad Roberts. Splitter now is bidirectional. Also Splitter has one extra trailing element if it ends with a separator. Added variadic arguments for setUnion and setIntersection. Added functions setSymmetricDifference and largestPartialIntersection. Improved BinaryHeap's interface and implementation.
  • std.array: Improvements to Appender. Now it works with string and other immutable-element arrays, and accepts ranges in put().
  • std.format: added raw specifier for reading
  • std.range: Added iota with two arguments. Added FrontTransversal and Transversal.
  • std.stdio: added File.byChunk
  • std.traits: Added isImplicitlyConvertible.
  • std.tuple: Added Tuple.opComp.
  • Folded in compiler changes by Unknown W. Brackets to support Solaris.
  • added .typeinfo to ClassInfo Bugzilla 2836: Navigate from ClassInfo to TypeInfo

Bugs Fixed

  • Fix instruction scheduler bug on Linux
  • unlisted: made std.numeric.entropy work on const/immutable arrays
  • Fixed several problems associated with thread local storage
  • 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 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 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 2580: Documented WinMain for D2 is wrong
  • Bugzilla 2633: incorrect ModuleInfo declaration in object.di
  • Bugzilla 2695: pure functions can invoke impure function pointers
  • Bugzilla 2807: Marking a nested function as 'pure' may cause bad code generations silently accepted
  • Bugzilla 2821: struct alignment inconsistent with C for { int, long }
  • Bugzilla 2851: Segfault using C-style struct initializer with too few arguments
  • Bugzilla 2865: RandomCover not random
  • Bugzilla 2882: std.random.MersenneTwisterEngine without seed
  • Bugzilla 2890: deadlock in std.stdio
  • Bugzilla 2893: qualified types don't have an Unsigned counterpart
  • Bugzilla 2906: writef problem with formatting floating point
  • Bugzilla 2914: to!string(struct) is broken
  • Bugzilla 2920: recursive templates blow compiler stack
  • Bugzilla 2922: Egregiously bad hashing performance with strings
Version D 2.029 Apr 19, 2009

New/Changed Phobos

  • std.algorithm
    • Everything converted to ranges. Big disruption. Algorithms added.
  • std.array
    • Range primitives for arrays
    • Appender template
    • insert, replace functions
  • std.bitmanip
    • Bitfields of length 0 are defined to be always 0.
    • The read functions for bitfields are const.
  • std.contracts
    • enforce accepts const(char)[] instead of string
    • Added enforce overload that invokes a delegate on failure
    • Added assumeSorted template
    • Added structuralCast that implements, well, structural casting (incomplete).
  • std.conv
    • Rewrote conversions with constrained templates.
    • Added text() function that transforms everything into text.
  • std.date
    • Added a benchmark function that allows for simple timing measurements.
  • std.file
    • read, write, append, rename, remove, getSize, getTimes, getAttributes, isfile, isdir, chdir, mkdir, mkdirRecurse, rmdir, listdir, copy, take filename(s) by "in char[]"
    • Added function readText that reads and validates a text file
    • Added function slurp that reads a file into an array of tuples. Example:
      auto a = slurp!(int, double)("filename", "%s, %s");
      Each line in the file looks like e.g. "1, 2.3". slurp returns an array of Tuple!(int, double) with the parsed content.
  • std.format
    • Added vector parsing and printing with the specifier "%()". For example, writefln("[%(s; )]", [1, 2, 3][]) writes "[1; 2; 3]". This support is experimental and may be changed in the future.
    • Added a formattedRead function (i.e., scanf that doesn't suck). The implementation is incomplete but common cases are supported.
  • std.functional
    • Improved error messages
    • Added configurable parameter names for functions as strings
    • Added Adjoin template
  • std.getopt
    • Added support for parameterless delegates
  • std.math
    • Intrinsics std.math.yl2x and yl2xp1 added. Improves performance of std.math.log() and similar functions (and they are now pure nothrow).
  • std.mmfile
    • Minor cosmetic changes
  • std.numeric
    • Added type CustomFloat that allows defining specialized floating-point numbers (e.g. 16-bit floats, positive floats etc.)
    • Added FPTemporary as the best type to store temporary values.
    • Templatized oppositeSigns
    • Added Euclidean distance
    • Added dotProduct
    • Added cosineSimilarity
    • Added normalize
    • Added string kernel functions gapWeightedSimilarity, gapWeightedSimilarityNormalized, gapWeightedSimilarityIncremental.
  • std.outbuffer
    • Added a few missing overloads of write()
  • std.path
    • getDrive now works with all string types
    • isabs accepts in char[]
    • join accepts variadic in char[]
    • fnmatch works with in char[]
  • std.random
    • Added RandomCover that covers a given range in a random manner
    • Eliminated the old-fashioned random functions
    • Defined a default random object that simplifies calls to the random functions
    • Changed generators to obey the range interface. So now you can write:
      Random r;
foreach (n; take(100, uniform(0, 100))) { ... }
  • std.range (new file)
    • Range manipulation stuff.
  • std.regex (new file)
    • Regular expression library with wide char support, simplified interface, better speed etc.
  • std.regexp
    • Scheduled for deprecation. Use std.regex instead.
  • std.stdio
    • Major breaking changes: introduced the File struct. Now stdin, stdout, stderr are instances of the File struct.
    • Due to bugs in the compiler, the copy constructor and destructor of File are commented out. Walter will look into fixing the issues soon. File should work fine, but you need to close it manually.
    • A byRecord iteration mode makes it pretty easy to iterate structured text files.
    • writef and writefln now require a string as their first argument.
  • std.string
    • strip, stripl, stripr, startsWith, endsWith now work with any string type
  • std.typecons
    • Added constructors, assignment operator, length, toString, and slice to Tuple.
  • std.utf
    • toUTF16z accepts in char[]
  • std.variant
    • Added support for Variants that contain vectors and hashes of themselves
  • std.c.stdio
    • Added fopen64 and friends

New/Changed Features

  • Added template function literals

Bugs Fixed

  • Bugzilla 675: %a format has an out-by-1 bug for denormals
  • Bugzilla 2199: Segfault using array operation in function call
  • Bugzilla 2203: typeof(class.template.foo) crashes compiler
  • Bugzilla 2577: DMD crashes on foreach of undefined identifier
  • Bugzilla 2808: 'nothrow' nested functions cannot be parsed
  • Bugzilla 2812: sqrt(2.0) is about -2.7341e-53
Version D 2.028 Apr 7, 2009

New/Changed Features

Bugs Fixed

  • Bugzilla 1586: DMD and GDC segfaults on incomplete code segment
  • Bugzilla 2064: Segfault with mixin(for/foreach) with empty loop body
  • Bugzilla 2812: sqrt(2.0) is about -2.7341e-53
  • Bugzilla 2804: Impure nested functions should be legal inside pure functions
Version D 2.027 Mar 31, 2009

New/Changed Features

  • Most functions in std.math are now pure nothrow. Improved speed of std.math.hypot.
  • Added response files for Linux and OSX
  • Added alias this
  • Bugzilla 2746: Make float.init signalling NaN by default
  • 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
  • Removed etc.gamma from the library.

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 1645: can override base class' const method with non-const method
  • Bugzilla 2319: "Win32 Exception" not very useful
  • Bugzilla 2336: link to nonexistent std_array.html
  • Bugzilla 2570: Patch for some mistakes in Ddoc comments
  • Bugzilla 2574: std.c.stdio doesn't compile: va_list not defined!
  • Bugzilla 2591: custom allocator new argument should be size_t instead of uint
  • Bugzilla 2595: template ctors crash compiler
  • Bugzilla 2596: Variadic constructors don't compile
  • Bugzilla 2626: template function not working against template struct instantiated with default arguments
  • Bugzilla 2674: Copy postblit constructor this(this) not called for members
  • Bugzilla 2689: seek behaves incorrectly on MAC OSX
  • Bugzilla 2692: alignment of double on x86 linux is incorrect
  • Bugzilla 2700: typeof tests stops compilation abruptly
  • 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 2722: ICE with variadic template parameters
  • Bugzilla 2723: ICE with variadic template parameters, different case
  • Bugzilla 2724: Persistent segfaults in templated code
  • Bugzilla 2725: Pattern matching in static if not working with variadic arguments
  • Bugzilla 2727: std.date Cyclic dependency
  • Bugzilla 2728: Bogus Error message on const ref return
  • Bugzilla 2729: hash_t undocumented and unnecessary
  • Bugzilla 2730: Restriction on op= can be lifted
  • Bugzilla 2731: Errors in associative array example
  • Bugzilla 2739: _argptr is invalid for functions nested in class methods
  • 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 2752: std.xml does not encode CData correctly
  • Bugzilla 2754: The error message regarding implicit conversion to shared doesn't mention shared in the message.
  • Bugzilla 2755: ICE on invalid ref returns in linked objects: Assertion failure: 'type' on line 6566 in file 'expression.c'. No ICE or error if invalid code is local to the file.
  • Bugzilla 2756: Bad code generation for pure nothrow math functions
  • Bugzilla 2761: Unreachable statement warning in std.string
  • Bugzilla 2763: std.mangle.demangle not translating 'ya'
  • Bugzilla 2766: DMD hangs with 0%cpu
  • Bugzilla 2767: DMD incorrectly mangles NTFS stream names
  • Bugzilla 2772: lib can't open response file
Version D 2.026 Mar 3, 2009

New/Changed Features

  • Escape string literals deprecated, see Bugzilla 2658
  • Tripled speed of exp, expm1, and exp2. std.math is now less dependent on the C standard library.
  • Added nested structs.
  • Added buildable dmd source.
  • Many changes to std.math for speed, accuracy, and Tango compatibility:
    • Improved accuracy of exp, expm1, exp2, sinh, cosh, tanh on Mac OSX, and tripled speed on all platforms.
    • Now using IEEE754-2008 camelCase names for isNaN, isFinite, isNormal, isSubnormal, isInfinity. Aliases for the old names have been retained.
    • The non-functional nan(char[]) is replaced with NaN, getNaNpayload.

Bugs Fixed

  • Bugzilla 1603: String literals bind to pointer types
  • 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 2597: auto return doesn't work for a variety of cases
  • Bugzilla 2612: immutable not accepted wherever invariant is
  • Bugzilla 2619: Locally-instantiated structs are not instantiated locally
  • Bugzilla 2621: ref binds to rvalues of user-defined types
  • Bugzilla 2622: ref returns not allowed in complex template
  • Bugzilla 2623: Function type drops ref spec
  • Bugzilla 2670: std.file.read() should read files of 0 length
  • Bugzilla 2673: Static constructors sometimes do not run when compiling with -lib
  • Bugzilla 2675: cannot foreach structs with copy constructor
  • Bugzilla 2676: alias parameters not matched in concept if clause
  • Bugzilla 2677: Alias type parameters not visible in concept-if clauses
  • Bugzilla 2678: for loops are already assumed to terminate
  • Bugzilla 2679: Spurious "warning - " messages and erratic behaviour with is(typeof({void function}()))
  • Bugzilla 2684: Associative arrays have wrong opIndex signatures
  • Bugzilla 2690: DMD aborts with MALLOC_CHECK_ set
Version D 2.025 Feb 14, 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

  • Bugzilla 2448: template return by reference causes seg fault
Version D 2.023 Jan 2, 2009

New/Changed Features

  • Improved speed of long division.
  • Optimizer now takes advantage of immutable and pure.
  • Added predefined version D_Ddoc which is predefined when -D switch is thrown.
  • the type of a string literal is now invariant(char)[] rather than invariant(char)[length_of_string]. It is still implicitly convertible to the latter. This is intended to reduce template instantiation bloat.
  • Undid fix for Bugzilla 2500, as the fix was arguably worse than the bug.

Bugs Fixed

  • Bugzilla 1078: Frontend uses of 'auto' where 'scope' should be used
  • 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 2533: compiler falls with "assertion failed" message on wrong code
  • Bugzilla 2534: dmd.conf is wrong
  • Bugzilla 2537: compiler crashes on this code:
  • Bugzilla 2541: cannot use aliased type for decl of foreach variable
  • Bugzilla 2542: array casts behave differently at compile and runtime
Version D 2.022 Dec 11, 2008

New/Changed Features

  • Changed IUnknown to use the extern(System) interface rather that extern(Windows).
  • Pure functions now get semantically checked.
  • Nothrow functions now get semantically checked.
  • shared is now a type constructor.

Bugs Fixed

  • Bugzilla 1518: Crash using 'scope', 'with' and undefined 'RegExp'
  • Bugzilla 1649: Variant coercion fails with delegates
  • Bugzilla 1685: Array index is evaluated twice
  • Bugzilla 1933: Delimited string constants can cause segfault
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2041: Spec implies relationship between interfaces and COM objects
  • Bugzilla 2105: added patch
  • Bugzilla 2441: header file generation translates enum to manifest
  • 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 2491: druntime GC wrongly frees data pointed to by TLS.
  • 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
  • Bugzilla 2503: Error 42: Symbol Undefined _D3std7process6systemFAyaZi
  • Bugzilla 2506: Can't initialize const member in ctor if it is accessed via this.member syntax
  • Incorporated some of the patches from Bugzilla 1752
  • extern __thread now works on Linux.
Version D 2.021 Nov 25, 2008

New/Changed Features

  • Added -safe switch and module(system) Identifier; syntax.
  • Added range support to foreach statement.
  • scope parameter storage class means the parameter will not 'escape' the scope of the function invocation. Using this for delegate parameters will prevent some closure allocations by the calling function.
  • The lazy storage class now implies scope so that lazy arguments won't trigger a heap allocated closure.
  • The 'this' parameter to struct member functions is now a reference type, rather than a pointer. This breaks existing code.
  • More changes to druntime:
    from | to
    OutOfMemoryException | OutOfMemoryError
    SwitchException | SwitchError
    HiddenFuncException | HiddenFuncError
    ArrayBoundsException | RangeError
    AssertException | AssertError
    FinalizeException | FinalizeError
    onArrayBoundsError | onRangeError
    stdc.* | core.stdc.*
    sys.* | core.sys.*
  • Added core.runtime.loadLibrary() as an experimental feature for loading dynamic libraries (Win32 only at the moment).
  • Added core.runtime.unloadLibrary() as an experimental feature for unloading dynamic libraries previously loaded by loadLibrary().
  • core.thread.sleep() accepts a long integer specifying the sleep interval in 100 nanosecond intervals (the previous release notes said this was a float, IIRC).
  • It is no longer necessary to link in druntime separately, it is inserted into libphobos2.a.

Bugs Fixed

  • Bugzilla 313: Fully qualified names bypass private imports
  • Bugzilla 920: SPEC: Auto classes referenced where scope should be used
  • 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 2428: Accessing item in enum'd array produced compiler error
  • 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 2.020 Oct 20, 2008

New/Changed Features

  • Improved performance of AAs by rebalancing trees when rehashing.
  • immutable now is implemented.
  • Bugzilla 2344: Two wrong lookups for array functions
  • Bugzilla 2345: Return by reference should be allowed
  • Posix is now a predefined identifier when compiling under Linux
  • Based on Sean Kelly's hard work, Phobos has been split into two libraries, druntime.lib and phobos.lib. This will enable better integration with Tango. The user source code changes are:
    from | to
    bit | bool
    _d_OutOfMemory() | onOutOfMemoryError()
    import std.asserterror; | import core.exception;
    import std.hiddenfunc; | import core.exception;
    import std.switcherr; | import core.exception;
    import std.array; | import core.exception;
    import std.outofmemory; | import core.exception;
    import std.gc; | import core.memory;
    import std.thread; | import core.thread;
    SwitchError | SwitchException
    AssertError | AssertException
    HiddenFuncError | HiddenFuncException
    ArrayBoundsError | ArrayBoundsException
    std.gc.fullCollect() | GC.collect()
    std.gc.*() | memory.gc_*()
    _moduleUnitTests() | import runtime; runModuleUnitTests()
    printf | add import std.c.stdio;
    Changes to thread:
    • The thread handle isn't exposed to the user. This can always be obtained using the appropriate OS calls from within the thread.
    • There is no druntime equivalent for Thread.pause() and Thread.resume(). The closest is thread_suspendAll() and thread_resumeAll()--extern (C) calls meant for use by the GC.
    • Thread.wait() is renamed to Thread.join().
    • Sleep functionality is available as Thread.sleep(double), where the parameter represents the number of seconds to sleep (fractional values accepted, obviously).
    This is a big change, and expect some problems for a release or two with this.

Bugs Fixed

  • Bugzilla 1229: Linker fills disk
  • Bugzilla 2332: Initializing const or invariant hashes croaks
  • Bugzilla 2333: Hash initializer does not work
  • Bugzilla 2336: link to nonexistent std_array.html
  • Bugzilla 2340: Template properties don't work
  • Bugzilla 2341: Double destruction without intervening copy
  • Bugzilla 2362: Confusing description of 'aliasing of invariant with mutable'?
  • Bugzilla 2363: Spurious () required after function name when used with array in prefix form
  • Bugzilla 2366: Const member function syntax is missing
  • 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 2.019 Sep 2, 2008

New/Changed Features

  • Added struct constructors.
  • Special member functions _ctor, _dtor, etc., now have two leading _ in order to not conflict with the user identifier space.

Bugs Fixed

  • Bugzilla 1322: foreach bypasses invariant
  • Bugzilla 1615: inout is allowed in foreach of string literal
  • Bugzilla 1627: ICE with a method called _ctor
  • Bugzilla 1633: Nonsensical "C style cast illegal" message with !is
  • 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 2190: toHash documentation is deprecated [D2.0]
  • 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 2287: std.conv should accept structs defining toString
  • Bugzilla 2289: Stack overflow on very large BigInt to string.
  • 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 2316: std.file docs are out of date
  • Bugzilla 2317: asm offsetof generates: Internal error: ../ztc/cod3.c 2651
Version D 2.018 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 1644: Template instantiation should automatically cast to const to make const-ness irrelevant when argument is const anyways
  • Bugzilla 2216: bad code generation for static arrays of zero length static arrays
  • Bugzilla 2223: Typo in error message
  • Bugzilla 2231: missing bigint document
  • 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 2266: opEquals documentation still says it returns int
  • Bugzilla 2269: D BUG: cosine of complex
  • Bugzilla 2272: synchronized attribute documentation
  • Bugzilla 2273: Whitespace is not inserted after commas
Version D 2.017 Jul 11, 2008

New/Changed Features

Bugs Fixed

  • Bugzilla 2207: overload resolution fails with deprecation
  • Bugzilla 2208: Deprecated function declarations cannot use deprecated types
  • Bugzilla 2209: Typo in doc for offsetof
  • Bugzilla 2212: phobos itself should be able to be compiled with '-w' switch
  • Bugzilla 2264: typo in documentation regarding atof.
Version D 2.016 Jul 8, 2008

New/Changed Features

  • re-implemented internal.monitor in D. Rationalized internal.object
  • Bugzilla 288: changed return type of opEquals from int to bool. This necessitates doing a grep for opEquals and changing all the return values.
  • Added .__vptr and .__monitor properties for class objects for use in the internal runtime library.
  • Made rdmd's source available through svn, see http://dsource.org/projects/phobos/browser/trunk/tools/rdmd.d
  • Simplified std.algorithm by fusing together higher-order functions taking an alias and their counterparts taking a string
  • Added module std.array containing array operations: insert, erase, and replace
  • Changed the enforce's implementation to generate smaller code per call
  • Changed std.functional.binaryFun to work with strings and function aliases alike
  • In std.getopt, added optChar, assignChar, and endOfOptions, per popular demand :o|
  • In std.math, replaced a bunch of consts with enums
  • In std.numeric, added Don Clugston as author and operated minor documentation fixes
  • Improved std.stdio.chunks to take an iteration tally in addition to the chunk

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 870: contradictory error messages for templates
  • 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 1912: Error without line number (Tuple, invalid value argument)
  • Bugzilla 1936: Error with no line number (array dimension overflow)
  • Bugzilla 2076: asm: offset has wrong docs and error without line number
  • Bugzilla 2161: Modify compiler to pass array TypeInfo to _adEq and _adCmp instead of element TypeInfo
  • Bugzilla 2178: 3 errors without line number: typeof
  • Bugzilla 2188: man-or-boy test fails with access violation
  • Fixed bugs in std.file.rename and std.file.remove on Linux
  • Fixed documentation in std.typecons
Version D 2.015 Jun 17, 2008

New/Changed Features

  • Template alias arguments can now be literals.
  • Function templates can now deduce the return type if they are declared with auto.
  • Non-lvalues are no longer matched to ref and out parameters when overloading.
  • Relaxed hidden hijacking detection when hidden function is disjoint from overloading with any other virtual function in the hierarchy.
  • Added version identifier D_PIC when -fPIC switch is used.
  • Added Constraints to templates.

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 1947: ICE (Assertion failure: '0' on statement.c:123) with null mixin
  • Bugzilla 1963: -H creates broken headers
  • Bugzilla 2098: Outdated docs
  • Bugzilla 2099: Text and Sample Code Disagree (non-static local invariant declaration)
  • Bugzilla 2112: the type of undefined variable incorrectly assumed to be int
  • Bugzilla 2118: Inconsistent use of string vs invariant(char[]) in doc
  • Bugzilla 2123: Anonymous class crashes
  • Bugzilla 2129: foreach won't work with invariant limits
  • Bugzilla 2132: CTFE: can't evaluate ~= at compile time, D2 only.
  • Bugzilla 2133: anonymous enum without {} doesn't work as asm value
  • 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 2145: Phobos buildsystem unable to build html
  • 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 2.014 May 16, 2008

New/Changed Features

  • Added -man switch to browse manual.
  • Added -lib switch to generate library files. Also causes multiple object files to be generated from one source module.
  • 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.
  • Rewrote the rdmd utility to properly track dependencies and command-line compiler options (currently only working under Linux).
  • Changed the Phobos makefile linux.mak to take advantage of the new -lib feature. Improved full build speed by 3x.
  • std.algorithm: Changed the map() function so that it deduces the return type. Also map can be now curried.
  • std.contracts: Added file and line information to enforce. Added errnoEnforce that formats the error message according to errno. Added corresponding ErrnoException class.
  • std.conv: Made std.to curryable. Changed std.to to throw exception when object-to-object cast fails. Eliminated some superfluous printfs.
  • std.encoding: Added new functions encodedLength(dchar) and encode(dchar, ref E[])
  • std.encoding: Got rid of types Utf8, Utf16, Utf32, Ascii, Latin1, Windows1252. Introduced types AsciiChar, AsciiString, Latin1Char, Latin1String, Windows1252Char, Windows1252String.
  • std.encoding: For now commented out std.encoding.to.
  • std.file: Changed Boolean function signatures (e.g. exists) to return bool instead of int. Got rid of some gotos. Added the readText, lastModified, mkdirRecurse, and rmdirRecurse functions.
  • std.functional: Improved compose so it accepts an unbounded number of functions. Added the pipe function.
  • std.getopt: Added new option stopOnFirstNonOption. Also automatically expand dubious option groups with embedded spaces in them (useful for shebang scripts)
  • std.math: improved integral powers
  • std.md5: Improved signature of sum so it takes multiple arrays. Added getDigestString.
  • std.path: changed signatures of test functions from bool to int. Implemented rel2abs for Windows. Improved join so that it accepts multiple paths. Got rid of some gotos with the help of scope statements.
  • std.process: added getenv and setenv. Improved system() so it returns the exit code correctly on Linux.
  • std.random: added the dice function - a handy (possibly biased) dice.
  • std.typecons: Finalized and documented the stupendous Rebindable template.
  • std.utf: added the codeLength function. Got rid of some gotos.

Bugs Fixed

  • std.format: Fixed unlisted bug in raw write for arrays
  • std.getopt: Fixed unlisted bug in dealing with one-letter options with bundling disabled
  • Bugzilla 2014: fopen fails on large files.
  • Bugzilla 2031: Documentation: template value parameters
  • Bugzilla 2032: Documentation for creating a class on the stack is unintuitive
  • Bugzilla 2037: Article on hijacking is outdated
  • Bugzilla 2038: Remove hello2.html from samples directory
  • Bugzilla 2039: -ignore switch is missing from compiler docs
  • Bugzilla 2054: Const system broken on struct assignment.
  • Bugzilla 2055: (ICE) Compiler crash on struct initializer with too many elements
  • Bugzilla 2056: Const system does not allow certain safe casts/conversions involving deep composite types
  • Bugzilla 2058: Describe hidden value passed to class member functions
  • Bugzilla 2063: std.xml access violation for nested, closed tags
  • Bugzilla 2065: Return value of std.file.exists() is inverted.
  • Bugzilla 2067: call from anonymous class makes access violation.
  • Bugzilla 2071: spec doesn't mention pointer arithmetic with two pointer operands
  • Bugzilla 2072: std.typecons documentation anomaly.
  • Bugzilla 2074: Variant arithmetic operations fail. For now the fix is to comment out all right-hand side operators. Suggestions for a better fix are welcome.
  • 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
  • Bugzilla 2100: Assertion failure: '0' on line 4842 in file 'expression.c'
  • Bugzilla 2109: asm {lea EAX, [0*0+EAX]; } rejected.
Version D 2.013 Apr 22, 2008

New/Changed Features

  • Added -ignore switch to ignore unsupported pragmas.
  • Unsupported pragmas now printed out with -v switch.
  • Added opDot, which is experimental only.
  • SwitchStatements can now accept runtime initialized const and invariant case statements.
  • Changed __FILE__ and __LINE__ so they work as parameter default initializers.
  • Incorporated Benjamin Shropshire's doc changes
  • Hidden methods now get a compile time warning rather than a runtime one.
  • Html source files are now deprecated.
  • Added pure and nothrow function attributes, although their semantics are not implemented.
  • Deprecated VolatileStatement; use SynchronizedStatement instead.
  • Added __thread storage class for thread local storage. This is for testing purposes only to check out the machinery in the back end. The front end design of this will change.
  • obj2asm and dumpobj now better handle special ELF fixup records.
  • Added partial ordering rules to disambiguate function overloading.
  • std.perf: Bill Baxter cleaned it up.
  • std.xml.Document constructor now creates whole DOM tree.
  • Added std.encoding.

Bugs Fixed

  • D/69085: const/invariant bug?
  • Bugzilla 1712: vtbl[0] for interface not set to corresponding Interface*
  • Bugzilla 1723: __traits(getVirtualFunctions) on a non-function fails badly
  • 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 1925
  • 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 2016: 'invariant' TypeSpecialization is missing
  • Bugzilla 2019: Appending a one-element array literal doesn't work
Version D 2.012 Mar 6, 2008

New/Changed Features

  • Added predefined version(unittest). See Bugzilla 458
  • Removed std.math2
  • Added compile time error for comparing class types against null.
  • Added struct destructors and postblits.
  • std.algorithm: Made some imports conditional for the Unittest version; fixed doc typo; made min and max always return the tightest type and work with mixes of signed and unsigned; changed enum value names to obey lowercase convention; changed OrderStrategy to SwapStrategy as it's not just for ordering (e.g. see eliminate).
  • std.bitmanip: simplified code generated for bitfields and improved error message.
  • std.format: ate dogfood: used bitfields internally.
  • std.functional: fixed binaryfun to work with constant-size arrays; added compose.
  • std.random: made unpredictableSeed return different numbers every call (except for rarely-encountered MT scenarios); added private variable name that will take experts millenia to figure out; changed the boundaries syntax from two separate characters '[', '(' to one string "[(" throughout.
  • std.traits: added mostNegative, mostly to assuage for the unpardonable mistake of inheriting C++'s unpardonable mistake of defining "min" to mean very different things for floating-point types and integral types.
  • std.typecons: added undocumented Rebindable in preparation for opImplicitCast.
  • std.math:
    • Support for different CPU IEEE 'real' formats: 64-bit, 80-bit and 128-bit (quadruple) reals, both BigEndian and LittleEndian; partial support for non-IEEE 'doubledouble' reals.
    • Added implementation of nextafter Bugzilla 1722 and scalb for DMD-Windows.
    • Added nextUp(), nextDown()
    • Bugzilla 1881: feqrel nonsensical for non-real arguments.
    • internal functions isPosZero(), isNegZero() removed in favour of the more generally useful isIdentical().
    • asm versions of functions which were not implemented by DMD Windows: scalb, lrint.
    • added creal expi(real y) which is useful for simultaneous calculation of sin + cos.

Bugs Fixed

  • std.contracts: fixed unlisted bug in pointsTo.
  • std.conv: fixed bug related to number-to-number conversion (T.min hits again).
  • 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 1800: Compiler crash on enums nested in structs
  • Bugzilla 1801: Const structs should be assignable to non-const variables unless they contain references
  • Bugzilla 1806: "const" makes typesafe variadic arguments not work properly.
  • 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 1821: ICE when using __traits isSame on const/invariant variables
  • Bugzilla 1823: Implicit conversion to const on associative array
  • 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 1851: missing opCall? when cast away const struct
  • Bugzilla 1852: you get opCall missing when cast to a struct(diagnostic)
  • Bugzilla 1853: opCmp documentation really needs some examples
  • Bugzilla 1854: bug in new flow analysis (warnings on valid code)
  • Bugzilla 1857: Runtime segfault while profileing - jump to invalid code address
  • Bugzilla 1862: asm: [ESI+1*EAX] should be a legal addr mode
  • Bugzilla 1865: Escape sequences are flawed.
  • Bugzilla 1867: lazy adds spurious const qualifier
  • Bugzilla 1871: DMD debug messages printed
  • Bugzilla 1873: structs with at least one immutable member are completely immutable
  • Bugzilla 1874: __traits(allMembers, T) fails to list methods which only have non-mutating overloads
  • Bugzilla 1876: inside a non-static class method, should "&( f)" be same as "&(this.f)" ?
  • Bugzilla 1877: Errors in the documentation of std.math.atan2
  • Bugzilla 1882: Internal error: ..\ztc\cod1.c 2529
  • Bugzilla 1883: templates instantiated as real gives incorrect values
  • Bugzilla 1884: manifest constants for strings
  • Bugzilla 1885: Syntax error for object identity test between invariant/mutable references
  • Bugzilla 1887: compiler freeze on array of dyn. arrays with empty first initializer
Version D 2.011 Feb 18, 2008

New/Changed Features

  • std.typecons: fixed code bloat issue; added Tuple.toString; added function tuple(); fixed unlisted bug in enumValuesImpl.
  • std.process: added function shell().
  • std.math: minor change in approxEqual.
  • std.contracts: added functions pointsTo()
  • std.numeric: minor unittest fixes.
  • std.bitmanip: fixed code bloat issue, reintroduced FloatRep and DoubleRep.
  • std.conv: minor simplification of implementation.
  • std.regexp: added reference to ECMA standard in the documentation.
  • std.getopt: changed return type from bool to void, error is signaled by use of exceptions.
  • std.functional: added unaryFun, binaryFun, adjoin.
  • std.string: updated documentation, changed code to compile with warnings enabled.
  • std.traits: changed FieldTypeTuple; added RepresentationTypeTuple, hasAliasing; fixed bug 1826; added call to flush() from within write; fixed unlisted bug in lines().
  • std.algorithm: added map, reduce, filter, inPlace, move, swap, overwriteAdjacent, find, findRange, findBoyerMoore, findAdjacent, findAmong, findAmongSorted, canFind, canFindAmong, canFindAmongSorted, count, equal, overlap, min, max, mismatch, EditOp, none, substitute, insert, remove, levenshteinDistance, levenshteinDistanceAndPath, copy, copyIf, iterSwap, swapRanges, reverse, rotate, SwapStrategy, Unstable, Semistable, Stable, eliminate, partition, nthElement, sort, schwartzSort, partialSort, isSorted, makeIndex, schwartzMakeIndex, lowerBound, upperBound, equalRange, canFindSorted.
  • std.thread: fixed so it compiles with warnings enabled.
  • std.file: made getSize() faster under Linux.
  • std.random: fixed so it compiles with warnings enabled; improved function uniform so it deduces type generated from its arguments.
  • std.format: added fixes to make formatting work with const data.
  • std.path: minor documentation changes.
  • Added std.xml
  • Added std.complex
  • Added std.iterator
  • Added std.c.linux.tipc
  • Added std.c.linux.termios
  • Added nothrow keyword
  • Re-enabled auto interfaces.
  • Now allow static arrays to be lvalues.
  • Now allows implicit casting of null to/from const/invariant.
  • Now allows implicit casting of StructLiterals if each of its arguments can be implicitly cast.
  • Now allows implicit casting of structs to/from const/invariant if each of its fields can be.
  • Added pragma startaddress.
  • .tupleof can now access private fields of a struct/class
  • Enhancement Bugzilla 493: Partial IFTI does not work

Bugs Fixed

  • Fixed D/66406 Remaining const niggles #1 - Custom POD types
  • Fixed display of ddoc template parameters that were aliased
  • Fixed bug in std.file.readln() for Windows in translated mode
  • Bugzilla 1072: CTFE: crash on for loop with blank increment
  • Bugzilla 1435: DDoc: Don't apply DDOC_PSYMBOL everywhere
  • Bugzilla 1815: foreach with interval does not increment pointers correctly
  • 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 2.010 Jan 20, 2008

New/Changed Features

  • opAssign can no longer be overloaded for class objects.
  • WinMain and DllMain can now be in template mixins.
  • Added pure keyword.

Bugs Fixed

  • Bugzilla 1319: compiler crashes with functions that take const ref arguments
  • Bugzilla 1697: Internal error: ..\ztc\cgcod.c 2322 with -O
  • Bugzilla 1700: ICE attempting to modify member of const return struct
  • Bugzilla 1707: '==' in TemplateParameterList in IsExpression causes segfault
  • Bugzilla 1711: typeof with delegate literal not allowed as template parameter
  • Bugzilla 1713: foreach index with tuples and templates fails
  • Bugzilla 1718: obscure exit with error code 5
  • Bugzilla 1719: Compiler crash or unstable code generation with scoped interface instances
  • Bugzilla 1720: std.math.NotImplemented missing a space in message
  • Bugzilla 1724: Internal error: toir.c 177
  • Bugzilla 1725: std.stream.BufferedFile.create should use FileMode.OutNew
  • Bugzilla 1757: there is an fault in phobos windows api interface
  • Bugzilla 1762: Wrong name mangling for pointer args of free extern (C++) functions
  • 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
  • D.announce/11066: Re: DMD 1.025 and 2.009 releases
Version D 2.009 Jan 1, 2008

New/Changed Features

  • Redid const/invariant semantics again.
  • Extended enums to allow declaration of manifest constants.

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 1694: Zip::ArchiveMember::name format bug
  • Bugzilla 1702: ICE when identifier is undefined
  • 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 1745: Internal error: ..\ztc\out.c 115
  • Bugzilla 1749: std.socket not thread-safe due to strerror
  • Bugzilla 1753: String corruption in recursive CTFE functions
  • D/63456: Cannot overload on constancy of this
Version D 2.008 Nov 27, 2007

New/Changed Features

  • std.string: Made munch more general and added function chompPrefix.
  • std.variant: Added documentation for variantArray
  • std.traits: Added CommonType template, fixed isStaticArray.
  • std.bitarray: scheduled for deprecation
  • std.bitmanip: new module with the content of std.bitarray plus the bitfields, FloatRep, and DoubleRep templates
  • std.process: Made getpid visible in Linux builds
  • std.math: Made nextafter visible for all floating types. Added approxEqual template.
  • std.contracts: Added enforce signature taking an exception
  • std.conv: Made conv_error a template parameterized on the types being converted.
  • std.stdio: Cosmetic changes.
  • std.system: Cosmetic changes.
  • std.file: Fixed bug in function dirEntries.
  • std.random: Major addition of engines and distributions.
  • std.format: Added raw ('r') format specifier for writef*.
  • std.path: Added rel2abs (Linux version only).
  • std.algorithm: new module
  • std.typecons: new module
  • std.functional: new module
  • std.numeric: new module
  • Added const/invariant structs, classes and interfaces.
  • Added const and invariant to IsExpressions.
  • Added typeof(return) type specifier.
  • Changed the way coverage analysis is done so it is independent of order dependencies among modules.
  • Revamped const/invariant.

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 1651: .di file generated with -H switch does not translate function() arguments correctly
  • Bugzilla 1655: Internal error: ..\ztc\cgcod.c 1817
  • Bugzilla 1656: illegal declaration accepted
  • Bugzilla 1664: (1.23).stringof generates bad code
  • Bugzilla 1665: Internal error: ..\ztc\cod2.c 411
Version D 2.007 Oct 31, 2007

New/Changed Features

  • Functors now supported by std.traits.ReturnType().
  • Transitive const now leaves invariants intact in the tail.
  • Added overloadable unary * operation as opStar().
  • Full closure support added.
  • Data items in static data segment >= 16 bytes in size are now paragraph aligned.

Bugs Fixed

  • Variables of type void[0] can now be declared.
  • Static multidimensional arrays can now be initialized with other matching static multidimensional arrays.
  • 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 1258: Garbage collector loses memory upon array concatenation
  • Bugzilla 1480: std.stream throws the new override warning all over the place
  • Bugzilla 1483: Errors in threads not directed to stderr
  • Bugzilla 1557: std.zlib allocates void[]s instead of ubyte[]s, causing leaks.
  • Bugzilla 1580: concatenating invariant based strings should work
  • 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 2.006 Oct 16, 2007

New/Changed Features

  • Transformed all of string, wstring, and dstring into invariant definitions. Tons of changes in function signatures and implementations rippled through the standard library. Initial experience with invariant strings seems to be highly encouraging.
  • Implemented Overload Sets for functions and templates.
  • Added the std.getopt module that makes standards-conforming command-line processing easy.
  • Added the parse and assumeUnique to the std.conv module.
  • Added the dirEntries function to the std.file module.
  • Added the basename and dirname functions (which alias the less gainful names getBaseName and getDirectoryName to the std.path module.)
  • Added optional terminator to readln; added the convenience functions fopen and popen; added functions lines and chunks; all to the std.stdio module.
  • Added the munch function to the std.string module.
  • Fixed isStaticArray; added BaseClassesTuple, TransitiveBaseTypeTuple, ImplicitConversionTargets, isIntegral, isFloatingPoint, isNumeric, isSomeString, isAssociativeArray, isDynamicArray, isArray; all to the std.traits module.
  • Added the std.variant module.
  • Incorporated many of the Tango GC structural differences (much more to go still).
  • Added the std.contracts module.
  • Breaking change: std.stdio.writef can now only accept a format as its first argument.

Bugs Fixed

  • Bugzilla 1478: Avoid libc network api threadsafety issues
  • Bugzilla 1491: Suppress SIGPIPE when sending to a dead socket
  • Bugzilla 1562: Deduction of template alias parameter fails
  • Bugzilla 1571: Const on function parameters not carried through to .di file
  • Bugzilla 1575: Cannot do assignment of tuples
  • Bugzilla 1579: write[ln] fails for obj.toString()
  • Bugzilla 1580: Concatenating invariant based strings should work
Version D 2.005 Oct 1, 2007

New/Changed Features

  • std.math.sin, cos, tan are now evaluated at compile time if the argument is a constant.
  • Added Cristian Vlasceanu's idea for C++ interface for 'plugins'
  • Overhaul phobos linux.mak and add documentation build logic
  • Massive additions to std.conv
  • Add writeln() and write() to std.stdio

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 1456: Cannot use a constant with alias template parameters
  • Bugzilla 1474: regression: const struct with an initializer not recognized as a valid alias template param
  • 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 1530: Aliasing problem in DMD front end code
  • Bugzilla 1531: cannot access typedef'd class field
  • Bugzilla 1537: Internal error: ..\ztc\cgcod.c 1521
Version D 2.004 Sep 5, 2007

New/Changed Features

  • Added command line switches -defaultlib and -debuglib
  • Bugzilla 1445: Add default library options to sc.ini / dmd.conf
  • Changed result type of IsExpression from int to bool.
  • Added isSame and compiles to __traits.
  • Added optional TemplateParameterList to IsExpression.
  • Added warning when override is omitted.
  • Added std.hiddenfunc.
  • 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.
  • Added new syntax for string literals (delimited, heredoc, D tokens)
  • Added __EOF__ token

Bugs Fixed

  • Fixed D/56414
  • Bugzilla 961: std.windows.registry stack corruption
  • Bugzilla 1315: CTFE doesn't default initialise arrays of structs
  • Bugzilla 1342: struct const not accepted as initializer for another struct
  • 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 1421: Stack Overflow when using __traits(allMembers...)
  • Bugzilla 1423: Registry: corrupted value
  • Bugzilla 1436: std.date.getLocalTZA() returns wrong values when in DST under Windows
  • Bugzilla 1446: Missing comma in Final Const and Invariant page title
  • 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
  • Bugzilla 1468: A bug about stack overflow.
Version D 2.003 Jul 21, 2007

New/Changed Features

  • Added 0x78 Codeview extension for type dchar.
  • Moved next member from Object.Error to Object.Exception
  • Added ForeachRangeStatement
    • .
  • Added extern (System)
  • Added std.traits
  • 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 1300: Issues with struct in compile-time function
  • Bugzilla 1306: extern (Windows) should work like extern (C) for variables
  • Bugzilla 1318: scope + ref/out parameters are allowed, contrary to spec
  • Bugzilla 1320: Attributes spec uses 1.0 const semantics in 2.0 section
  • 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 2.002 Jul 1, 2007

New/Changed Features

  • Renamed linux library from libphobos.a to libphobos2.a

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 2.001 Jun 27, 2007

New/Changed Features

  • Added D_Version2 predefined identifier to indicate this is a D version 2.0 compiler
  • Added __VENDOR__ and __VERSION__.
  • Now an error to use both const and invariant as storage classes for the same declaration
  • The .init property for a variable is now based on its type, not its initializer.

Bugs Fixed

  • std.compiler now is automatically updated.
  • Fixed problem catting mutable to invariant arrays.
  • 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 1274: 2.0 beta link points to dmd.zip which is the 1.x chain
  • Bugzilla 1275: ambiguity with 'in' meaning
  • Bugzilla 1276: static assert message displayed with escaped characters
  • Bugzilla 1277: "in final const scope" not considered redundant storage classes
  • Bugzilla 1279: const/invariant functions don't accept const/invariant return types
  • Bugzilla 1280: std.socket.Socket.send (void[],SocketFlags) should take a const(void)[] instead
  • Bugzilla 1283: writefln: formatter applies to following variable
  • Bugzilla 1286: crash on invariant struct member function referencing globals
Version D 2.000 Jun 17, 2007

New/Changed Features

  • Added aliases string, wstring, and dstring for strings.
  • Added .idup property for arrays to create invariant copies.
  • Added const, invariant, and final.
  • in parameter storage class now means final scope const.
  • foreach value variables now default to final if not declared as inout.
  • class and struct invariant declarations now must have a ().

Bugs Fixed

  • Added missing \n to exception message going to stderr.
  • Fixed default struct initialization for CTFE.
  • Bugzilla 1226: ICE on a struct literal

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


D 2.0 Specific Features

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

D 2.0 Enhancements from D 1.0

D 2.0 has many substantial language and library enhancements compared with D 1.0. This list does not include bug fixes or changes that were also made to D 1.0. See the D1 to D2 Migration Guide for help in converting source code.

Core Language Changes

  • opAssign can no longer be overloaded for class objects.
  • Added pure keyword.
  • Extended enums to allow declaration of manifest constants.
  • Added const/immutable structs, classes and interfaces.
  • Added const and immutable to IsExpressions.
  • Added typeof(return) type specifier.
  • Added overloadable unary * operation as opStar().
  • Full closure support added.
  • Transformed all of string, wstring, and dstring into immutable definitions
    • .
  • Added Overload Sets for functions and templates.
  • std.math.sin, cos, tan are now evaluated at compile time if the argument is a constant.
  • Added C++ interface for ‘plugins’.
  • Changed result type of IsExpression from int to bool.
  • Added optional TemplateParameterList to IsExpression.
  • Added warning when override is omitted.
  • Added new syntax for string literals (delimited, heredoc, D tokens)
  • Added __EOF__ token
  • Added D_Version2 predefined identifier to indicate this is a D version 2.0 compiler
  • Added .idup property for arrays to create immutable copies.
  • Added transitive const and immutable.
  • in parameter storage class now means scope const.
  • class and struct invariant declarations now must have a ().
  • Added isSame and compiles to __traits.
  • Added ForeachRangeStatement
    • .

Phobos Library Changes

  • std.algorithm: new module
  • std.bitarray: scheduled for deprecation
  • std.bitmanip: new module with the content of std.bitarray plus the bitfields, FloatRep, and DoubleRep templates
  • std.contracts: new module
  • std.conv: Added parse and assumeUnique. Made conv_error a template parameterized on the types being converted. Massive additions.
  • std.file: added dirEntries.
  • std.format: Added raw ('r') format specifier for writef*.
  • std.functional: new module
  • std.getopt: new module.
  • std.hiddenfunc: new module
  • std.math: Made nextafter visible for all floating types. Added approxEqual template.
  • std.numeric: new module
  • std.path: Added rel2abs (Linux version only). Added the basename and dirname functions (which alias the less gainful names getBaseName and getDirectoryName)
  • std.process: Made getpid visible in Linux builds
  • std.stdio: Added writeln() and write(), writef() can now only accept a format as its first argument. Added optional terminator to readln. Added functions fopen, popen, lines and chunks.
  • std.string: Added munch function and added function chompPrefix.
  • std.random: Major addition of engines and distributions.
  • std.traits: new module
  • std.typecons: new module
  • std.variant: new module.
  • Incorporated many of the Tango GC structural differences (much more to go still).
  • Overhaul phobos linux.mak and add documentation build logic
  • Moved next member from Object.Error to Object.Exception
  • Renamed linux library from libphobos.a to libphobos2.a

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


Rationale

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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;

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


Warnings

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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.

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


Real Close to the Machine: Floating Point in D

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Real Close to the Machine: Floating Point in D

Introduction

by Don Clugston

Computers were originally conceived as devices for performing mathematics. The earliest computers spent most of their time solving equations. Although the engineering and scientific community now forms only a miniscule part of the computing world, there is a fantastic legacy from those former times: almost all computers now feature superb hardware for performing mathematical calculations accurately and extremely quickly. Sadly, most programming languages make it difficult for programmers to take full advantage of this hardware. An even bigger problem is the lack of documentation; even for many mathematical programmers, aspects of floating-point arithmetic remain shrouded in mystery.

As a systems programming language, the D programming language attempts to remove all barriers between the programmer and the compiler, and between the programmer and the machine. This philosophy is particularly evident in support for floating-point arithmetic. A personal anecdote may illustrate the importance of having an accurate understanding of the hardware.

My first floating-point nightmare occurred in a C++ program which hung once in every hundred runs or so. I eventually traced the problem to a while loop which occasionally failed to terminate. The essence of the code is shown in Listing 1.

double q[8];
...
int x = 0;
while (x < 8) {
  if ( q[x] >= 0 ) return true;
  if ( q[x] < 0 ) ++x;
}
return false;

Initially, I was completely baffled as to how this harmless-looking loop could fail. But eventually, I discovered that q had not been initialized properly; q[7] contained random garbage. Occasionally, that garbage had every bit set, which mean that q[7] was a Not-a-Number (NaN), a special code which indicates that the value of the variable is nonsense. NaNs were not mentioned in the compiler's documentation - the only information I could find about them was in Intel's assembly instruction set documentation! Any comparison involving a NaN is false, so q[7] was neither >= 0, nor < 0, killing my program. Until that unwelcome discovery, I'd been unaware that NaNs even existed. I had lived in a fool's paradise, mistakenly believing that every floating point number was either positive, negative, or zero.

My experience would have been quite different in D. The "strange" features of floating point have a higher visibility in the language, improving the education of numerical programmers. Uninitialized floating point numbers are initialized to NaN by the compiler, so the problematic loop would fail every time, not intermittently. Numerical programmers in D will generally execute their programs with the 'invalid' floating point exception enabled. Under those circumstances, as soon as the program accessed the uninitialized variable, a hardware exception would occur, summoning the debugger. Easy access to the "strange" features of floating point results in better educated programmers, reduced confusion, faster debugging, better testing, and hopefully, more reliable and correct numerical programs. This article will provide a brief overview of the support for floating point in the D programming language.

Demystifying Floating-Point

D guarantees that all built-in floating-point types conform to IEEE 754 arithmetic, making behaviour entirely predictable (note that this is not the same as producing identical results on all platforms). IEEE 754-2008 is the latest revision of the IEEE 754 Standard for Floating-Point Arithmetic. D is progressing towards full compliance with 754-2008.

The IEEE standard floating point types currently supported by D are float and double. Additionally, D supports the real type, which is either 'IEEE 80-bit extended' if supported by the CPU; otherwise, it is the same as double. In the future, the new types from 754-2008 will be added: quadruple, decimal64, and decimal128.

The characteristics of these types are easily accessible in the language via properties. For example, float.max is the maximum value which can be stored in a float; float.mant_dig is the number of digits (bits) stored in the mantissa.

To make sense of mathematics in D, it's necessary to have a basic understanding of IEEE floating-point arithmetic. Fundamentally, it is a mapping of the infinitely many real numbers onto a small number of bytes. Only 4000 million distinct numbers are representable as an IEEE 32-bit float. Even with such a pathetically small representation space, IEEE floating point arithmetic does a remarkably good job of maintaining the illusion that mathematical real numbers are being used; but it's important to understand when the illusion breaks down.

Most problems arise from the distribution of these representable numbers. The IEEE number line is quite different to the mathematical number line.

     +     +-----------+------------+    ..   +    ..    +----------+----------+     +       #
-infinity -float.max  -1  -float.min_normal   0   float.min_normal  1  float.max infinity  NaN

Notice that half of the IEEE number line lies between -1 and +1. There are 1000 million representable floats between 0 and 0.5, but only 8 million between 0.5 and 1. This has important implications for accuracy: the effective precision is incredibly high near zero. Several examples will be presented where numbers in the range -1 to +1 are treated seperately to take advantage of this.

Notice also the special numbers: ±∞; the so-called "subnormals" between ±float.min_normal and 0, which are represented at reduced precision; the fact that there are TWO zeros, +0 and -0, and finally "NaN"("Not-a-Number"), the nonsense value, which caused so much grief in Listing 1.

Why does NaN exist? It serves a valuable role: it eradicates undefined behaviour from floating-point arithmetic. This makes floating-point completely predictable. Unlike the int type, where 3/0 invokes a hardware division by zero trap handler, possibly ending your program, the floating-point division 3.0/0.0 results in ∞. Numeric overflow (eg, real.max*2) also creates ∞. Depending on the application, ∞ may be a perfectly valid result; more typically, it indicates an error. Nonsensical operations, such as 0.0 / 0.0, result in NaN; but your program does not lose control. At first glance, infinity and NaN may appear unnecessary -- why not just make it an error, just as in the integer case? After all, it is easy to avoid division by zero, simply by checking for a zero denominator before every division. The real difficulty comes from overflow: it is extremely difficult to determine in advance whether an overflow will occur in a multiplication.

Subnormals are necessary to prevent certain anomalies, and preserve important relationships such as: "x - y == 0 if and only if x == y".

Since ∞ can be produced by overflow, both +∞ and -∞ are required. Both +0 and -0 are required in order to preserve identities such as: if x>0, then 1/(1/x) > 0. In almost all other cases, however, there is no difference between +0 and -0.

It's worth noting that these ‘special values’ are usually not very efficient. On x86 machines, for example, a multiplication involving a NaN, an infinity, or a subnormal can be twenty to fifty times slower than an operation on normal numbers. If your numerical code is unexpectedly slow, it's possible that you are inadvertently creating many of these special values. Enabling floating-point exception trapping, described later, is a quick way to confirm this.

One of the biggest factor obscuring what the machine is doing is in the conversion between binary and decimal. You can eliminate this by using the "%a" format when displaying results. This is an invaluable debugging tool, and an enormously helpful aid when developing floating-point algorithms. The 0x1.23Ap+6 hexadecimal floating-point format can also be used in source code for ensuring that your input data is exactly what you intended.

The Quantized Nature of Floating-Point

The fact that the possible values are limited gives access to some operations which are not possible on mathematical real numbers. Given a number x, nextUp(x) gives the next representable number which is greater than x. nextDown(x) gives the next representable number which is less than x.

Numerical analysts often describe errors in terms of "units in the last place"(ulp), a surprisingly subtle term which is often used rather carelessly. [footnote: The most formal definition is found in [J.-M. Muller, "On the definition of ulp(x)",INRIA Technical Report 5504 (2005).]: If x is a real number that lies between two finite consecutive floating-point numbers a and b of type F, without being equal to one of them, then ulp(x)=abs(b-a); otherwise ulp(x) = x*F.epsilon. Moreover, ulp(NaN) is NaN, and ulp(±F.infinity) = ±F.max*F.epsilon.] I prefer a far simpler definition: The difference in ulps between two numbers x and y is is the number of times which you need to call nextUp() or nextDown() to move from x to y. [Footnote: This will not be an integer if either x or y is a real number, rather than a floating point number.] The D library function feqrel(x, y) gives the number of bits which are equal between x and y; it is an easy way to check for loss-of-precision problems.

The quantized nature of floating point has some interesting consequences.

  • ANY mathematical range [a,b), (a,b], or (a,b) can be converted into a range or the form [a,b]. (The converse does not apply: there is no (a,b) equivalent to [-∞, ∞]).
  • A naive binary chop doesn't work correctly. The fact that there are hundreds or thousands of times as many representable numbers between 0 and 1, as there are between 1 and 2, is problematic for divide-and-conquer algorithms. A naive binary chop would divide the interval [0 .. 2] into [0 .. 1] and [1 .. 2]. Unfortunately, this is not a true binary chop, because the interval [0 .. 1] contains more than 99% of the representable numbers from the original interval!

Condition number

Using nextUp, it's easy to approximately calculate the condition number.

real x = 0x1.1p13L;
real u = nextUp(x);

int bitslost = feqrel(x, u) - feqrel(exp(x), exp(u));

This shows that at these huge values of x, a one-bit error in x destroys 12 bits of accuracy in exp(x)! The error has increased by roughly 6000 units in the last place. The condition number is thus 6000 at this value of x.

The semantics of float, double, and real

For the x86 machines which dominate the market, floating point has traditionally been performed on a descendent of the 8087 math coprocessor. These "x87" floating point units were the first to implement IEEE754 arithmetic. The SSE2 instruction set is an alternative for x86-64 processors, but x87 remains the only portable option for floating point 32-bit x86 machines (no 32-bit AMD processors support SSE2).

The x87 is unusual compared to most other floating-point units. It _only_ supports 80-bit operands, henceforth termed "real80". All double and float operands are first converted to 80-bit, all arithmetic operations are performed at 80-bit precision, and the results are reduced to 64-bit or 32-bit precision if required. This means that the results can be significantly more accurate than on a machine which supports at most 64 bit operations. However, it also poses challenges for writing portable code. (Footnote: The x87 allows you to reduce the mantissa length to be the same as 'double or float, but it retains the real80 exponent, which means different results are obtained with subnormal numbers. To precisely emulate double arithmetic slows down floating point code by an order of magnitude).

Apart from the x87 family, the Motorola 68K (but not ColdFire) and Itanium processors are the only ones which support 80-bit floating point.

A similar issue relates to the FMA (fused multiply and accumulate) instruction, which is available on an increasing number of processors, including PowerPC, Itanium, Sparc, and Cell. On such processors, when evaluating expressions such as x*y + z, the x*y is performed at twice the normal precison. Some calculations which would otherwise cause a total loss of precision, are instead calculated exactly. The challenge for a high-level systems programming language is to create an abstraction which provides predictable behaviour on all platforms, but which nonetheless makes good use of the available hardware.

D's approach to this situation arises from the following observations:

  1. It is extremely costly performance-wise to ensure identical behaviour on all processors. In particular, it is crippling for the x87.
  2. Very many programs will only run on a particular processor. It would be unfortunate to deny the use of more accurate hardware, for the sake of portability which would never be required.
  3. The requirements for portability and for high precision are never required simultaneously. If double precision is inadequate, increasing the precision on only some processors doesn't help.
  4. The language should not be tied to particular features of specific processors.

A key design goal is: it should be possible to write code such that, regardless of the processor which is used, the accuracy is never worse than would be obtained on a system which only supports the double type.

(Footnote: real is close to ‘indigenous’ in the Borneo proposal for the Java programming language[Ref Borneo]).

Consider evaluating x*y + z*w, where x, y, z and w are double.

  1. double r1 = x * y + z * w;
  2. double a = x * y; double r2 = a + z * w;
  3. real b = x * y; double r3 = b + z * w;

Note that during optimisation, (2) and (3) may be transformed into (1), but this is implementation-dependent. Case (2) is particularly problematic, because it introduces an additional rounding.

On a "simple" CPU, r1==r2==r3. We will call this value r0. On PowerPC, r2==r3, but r1 may be more accurate than the others, since it enables use of FMA. On x86, r1==r3, which may be more accurate than r0, though not as much as for the PowerPC case. r2, however, may be LESS accurate than r0.

By using real for intermediate values, we are guaranteed that our results are never worse than for a simple CPU which only supports double.

Properties of the Built-in Types

The fundamental floating-point properties are epsilon, min_normal and max. The six integral properties are simply the log2 or log10 of these three.

 | float | double | real80 | quadruple | decimal64 | decimal128
epsilon | 0x1p-23 | 0x1p-52 | 0x1p-63 | 0x1p-112 | 1e-16 (1p-54) | 1e-34 (1p-113)
[min_normal | 0x1p-126 | 0x1p-1022 | 0x1p-16382 | 0x1p-16382 | 1e-383 | 1e-6143
..max) | 0x1p+128 | 0x1p+1024 | 0x1p+16384 | 0x1p+16384 | 1e+385 | 1e+6145
binary properties
mant_dig | 24 | 53 | 64 | 113 | 53 | 112
min_exp | -125 | -1021 | -16381 | -16381 |  |
max_exp | +128 | +1024 | +16384 | +16384 |  |
decimal properties
dig | 6 | 15 | 18 | 33 | 16 | 34
min_10_exp | -37 | -307 | -4932 | -4932 | -382 | -6142
max_10_exp | +38 | +308 | +4932 | +4932 | 385 | +6145

When writing code which should adapt to different CPUs at compile time, use static if with the mant_dig property. For example, static if (real.mant_dig==64) is true if 80-bit reals are available. For binary types, the dig property gives only the minimum number of valid decimal digits. To ensure that that every representable number has a unique decimal representation, two additional digits are required. Similarly, for decimal numbers, mant_dig is a lower bound on the number of valid binary digits.

Useful relations for a floating point type F, where x and y are of type F

  • The smallest representable number is F.min_normal * F.epsilon
  • Any integer between 0 and (1/F.epsilon) can be stored in F without loss of precision. 1/F.epsilon is always a exact power of the base.
  • If a number x is subnormal, x*(1/F.epsilon) is normal, and exponent(x) = exponent(x*(1/F.epsilon)) - (mant_dig-1).
  • x>0 if and only if 1/(1/x) > 0; x<0 if and only if 1/(1/x) < 0.
  • If x-y==0, then x==y && isFinite(x) && isFinite(y). Note that if x==y==infinity, then isNaN(x-y).
  • F.max * F.min_normal = 4.0 for binary types, 10.0 for decimal types.

Addition and subtraction

  • Some loss of precision occurs with x±y if exponent(x)!=exponent(y). The number of digits of precision which are lost is abs(exponent(x)-exponent(y)).
  • x±y has total loss of precision, if and only if (1) abs(x * F.epsilon) > abs(y), in which case x+y == x, x-y == x or (2) abs(y * F.epsilon) > abs(x), in which case x+y == y, x-y == -y
  • Addition is commutative: a + b == b + a.
  • Subtraction is not quite commutative: a - b == -(b - a), but produce +0 and -0 if a==b.
  • Addition is not associative at all.

Multiplication and division

  • Multiplication and division are always at risk of overflow or underflow. For any abs(x) > F.epsilon, there is at least one finite y such that x/y will overflow to ∞. For any abs(x) < F.epsilon, there is at least one finite y such that x/y will underflow to zero. For any abs(x) > 1, there is at least one finite y such that x*y will overflow to ∞. For any abs(x) < 1, there is at least one finite y such that x*y will underflow to zero.
  • x*x will overflow if abs(x)>sqrt(F.max), and underflow to zero if abs(x) < sqrt(F.min_normal*F.epsilon)
  • Multiplication is commutative. a * b == b * a
    • .
  • Multiplication is not associative in general: a*(b*c) != (a*b)*c, because (1) there is a risk of overflow or underflow and (2) b*c may be an exact calculation, so that a*(b*c) contains only one round-off error, whereas (a*b)*c contains two. The roundoff errors may therefore accumulate at the rate of just under 1 ulp per multiplication.
  • However, a limited form of associativity is possible if the type used for intermediate results is larger than any of the operands (which happens on x87 and Itanium machines). If R is the intermediate type, and F is the type being multiplied, up to min(R.max_exp/F.max_exp, R.epsilon/F.epsilon) values of type F can be multiplied together in any order without influencing the result. For example, if R is double, multiplication of 8 floats f1*f2*f3*f4*f5*f6*f7*f8 is completely associative. On x87, 130 floats can be safely multiplied together in any order, and 16 doubles can similarly be multiplied together safely. Strict distributivity does not hold even under these circumstances, as it may destroy the sign of -0.
  • The distributive law almost never holds. For example, 4*x + 6*x != 10*x if x==nextDown(1.5). a*x + b*x == (a+b)*x for all x only if the operations a*x, b*x, and (a+b) are all exact operations, which is true only if a and b are exact powers of 2. Even then, if a==-b and x==-0, then a*x+b*x==0.0, (a+b)*x==-0.0.
  • Performing a division by multiplication by the reciprocal returns a result which (in round-to-nearest mode) is at most 1.5 ulps from the correctly rounded result. For almost any denominator, the rounding is incorrect (>0.5ulps) for 27% of numerators. [Ref: N. Brisebarre, J-M Muller, and S.K. Raina, "Accelerating Correctly Rounded Floating-Point Division when the Divisor Is Known in Advance", IEEE Trans. on Computers, Vol 53, pp 1069-1072 (2004)].

Powers and logarithms

  • F.mant_dig = -log2(F.epsilon) for binary types;
  • F.dig = -log10(F.epsilon) for decimal types.
  • F.max = exp2(F.max_exp*(1-F.epsilon)) for binary types;
  • F.max = exp10(F.max_10_exp*(1-F.epsilon)) for decimal types.
  • For any positive finite x, F.min_exp - F.mant_dig <= log2(x) < F.max_exp for binary types, F.min_10_exp - F.dig <= log10(x) < F.max_10_exp for decimal types
  • exp2(x) == 0 if x < F.min_exp - F.mant_dig, exp2(x) == infinity if x >= F.max_exp

NaN payloads

According to the IEEE 754 standard, a ‘payload’ can be stored in the mantissa of a NaN. This payload can contain information about how or why it was generated. Historically, almost no programming languages have ever made use of this potentially powerful feature. In D, this payload consists of a positive integer.

  • real NaN(ulong payload) -- create a NaN with a "payload", where the payload is a ulong.
  • ulong getNaNPayload(real x) -- returns the integer payload. Note that if narrowing conversions have occured, the high-order bits may have changed.

Never store a pointer as an integer payload inside a NaN. The garbage collector will not be able to find it!

NCEG comparison operations

As well as the usual <, >, <=, and >= comparison operators, D also supports the "NCEG" operators. Most of them are the direct negation of the ordinary operators. Additionally, <>, <>=, !<>, and !<>= are provided. These 8 new operators are different from the normal operators only when a NaN is involved, so for the most part they are quite obscure. They are useful mainly in eliminating the possibility of NaN before beginning a calculation. The most useful relationships are probably:

  • x <>= y is the same as !isNaN(x) && !isNaN(y), (except that signalling NaNs may be triggered by <>=).
  • x !<>= y is the same as isNaN(x) || isNaN(y).
If y is any compile-time constant (eg 0), these reduce to !isNaN(x) and isNaN(x). Note that x==x is the same as !isNaN(x), and x!=x is the same as isNaN(x). abs(x) !< x.infinity is the same as isNaN(x) || isInfinity(x) The above relationships are useful primarily because they can be used in compile time functions. Very few uses are known for the remaining NCEG operators.

The IEEE Rounding Modes

The rounding mode is controlled within a scope. Rounding mode will be restored to its previous state at the end of that scope. Four rounding modes can be set. The default mode, Round to nearest, is the most statistically accurate, but the least intuitive. In the event of tie, the result is rounded to an even number.

Rounding mode | rndint(4.5) | rndint(5.5) | rndint(-4.5) | Notes
Round to nearest | 4 | 6 | -4 | Ties round to an even number
Round down | 4 | 5 | -5 |
Round up | 5 | 6 | -4 |
Round to zero | 4 | 5 | -4 |

There are very few reasons for changing the rounding mode. The round-up and round-down modes were created specifically to allow fast implementations of interval arithmetic; they are crucial to certain libraries, but rarely used elsewhere. The round-to-zero mode is used for casting floating-point numbers to integers. Since mode switching is slow, especially on Intel machines, it may be useful to switch to round-to-zero mode, in order to exactly duplicate the behaviour of cast(int) in an inner loop.

The only other commonly cited reason for changing the rounding mode is as a simple check for numerical stability: if the calculation produces wildly different results when the rounding mode is changed, it's a clear sign that it is suffering from round-off errors.

The IEEE Exception Status Flags

All IEEE-compiliant processors include special status bits that indicate when "weird" things have happened that programs might want to know about. For example, ieeeFlags.divideByZero tells if any infinities have been created by dividing by zero. They are 'sticky' bits: once they have been set, they remain set until explicitly cleared. By only checking this once at the end of a calculation, it may be possible to avoid comparing thousands of comparisions that are almost never going to fail.

Here's a list of the weird things that can be detected:

invalid
This is set if any NaN's have been generated. This can happen with ∞ - ∞, ∞ * 0, 0 * ∞, 0/0, ∞/∞, ∞%∞, or x%0, for any number x. Several other operations, such as sqrt(-1), can also generate a NaN. The invalid condition is also set when a 'signalling NaN' is accessed, indicating use of an uninitialized variable. This almost always indicates a programming error.
overflow
Set if ∞ was generated by adding or multiplying two numbers that were so large that the sum was greater than real.max. This almost always indicates that the result is incorrect; and corrective action needs to be taken.
divisionByZero
Set if ±∞ was generated by dividing by zero. This usually indicates a programming error, but not always; some types of calculations return correct results even when division by zero occurs. (For example, 1/(1+ 1/x) == 0 if x == 0). Note that division by a tiny, almost-zero number also produces an infinite result, but sets the overflow flag rather than the divisionByZero flag.
underflow
This happens if two numbers are subtracted or divided and are so tiny that the result lost precision because it was subnormal. Extreme underflow produces a zero result. Underflow almost never creates problems, and can usually be ignored.
inexact
This indicates that rounding has occurred. Almost all floating point operations set this flag! It was apparently included in the hardware to support some arcane tricks used in the pioneering days of numerical analysis. It can always be ignored.

Floating-point traps can be enabled for any of the categories listed above. When enabled, a hardware exception will be generated. This can be an invaluable debugging aid. A more advanced usage, not yet supported on any platform(!) is to provide a nested function to be used as a hardware exception handler. This is most useful for the overflow and underflow exceptions.

Floating point and ‘pure nothrow’

Every floating point operation, even the most trivial, is affected by the floating-point rounding state, and writes to the sticky flags. The status flags and control state are thus 'hidden variables', potentially affecting every pure function; and if the floating point traps are enabled, any floating point operation can generate a hardware exception. D provides a facility for the floating-point control mode and exception flags to be usable in limited circumstances even when pure and nothrow functions are called.

[TODO: I've made two proposals, but I haven't persauded Walter yet!].

Conclusion

Although D is a general-purpose programming language and supports many high-level concepts, it gives direct and convenient access to almost all features of modern floating-point hardware. This makes it an excellent language for development of robust, high-performance numerical code. It is also a language which encourages a deep understanding of the machine, making it fertile ground for innovation and for developing new algorithms.

References and Further Reading

  1. "What Every Computer Scientist Should Know About Floating-Point Arithmetic"
  2. "An Interview with the Old Man of Floating-Point: Reminiscences elicited from William Kahan by Charles Severance"
  3. N. Brisebarre, J-M Muller, and S.K. Raina, "Accelerating Correctly Rounded Floating-Point Division when the Divisor Is Known in Advance", IEEE Trans. on Computers, Vol 53, pp 1069-1072 (2004).
  4. "The Borneo language"

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


Migrating to Shared

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Migrating to Shared

Starting with dmd version 2.030, the default storage class for statics and globals will be thread local storage (TLS), rather than the classic global data segment. While most D code should just compile and run successfully without change, there can be some issues.

  1. Performance of TLS variables.
  2. Identifying TLS variables.
  3. Switch to Immutable.
  4. Marking as shared.
  5. Cowboying with __gshared.
  6. Compile errors.
  7. Link errors.

Performance of TLS variables

Yes, reading or writing TLS variables will be slower than for classic global variables. It'll be about 3 instructions rather than one. But on Linux, at least, TLS will be slightly faster than accessing classic globals using PIC (position independent code) compiler code generation settings. So it's hard to see that this would be an unacceptable problem. But let's presume it is. What can we do about it?

  1. Minimize use of global variables. Reducing the use of globals can improve the modularization and maintainability of the code anyway, so this is a worthy goal.
  2. Make them immutable. Immutable data doesn't have synchronization problems, so the compiler doesn't place it in TLS.
  3. Cache a reference to the global. Making a local cache of it, and then accessing the cached value rather than the original, can speed things up especially if the cached value gets enregistered by the compiler.
  4. Cowboy it with __gshared.

Identifying TLS variables

The first step is to find all the global variables, so they can be reviewed for disposition.

Given the complexity of source code, it isn't always easy to identify the global variables. Since it (used to be) implicit, there's no way to grep for them. It's hard to be sure you've found them all.

A new dmd compiler switch was added, -vtls. Compiling with it on will print a list of all the global variables that are now defaulting to thread local storage.

int x;

void main()
{
    static int y;
}

dmd test -vtls
test.d(2): x is thread local
test.d(6): y is thread local

Switch to Immutable

Immutable data, once initialized, never changes. This means that there are no synchronization issues with multithreading, and so no need to put immutable data into TLS. The compiler will put immutable data into classic global storage, not TLS.

A good chunk of global data falls into this category. Just mark it as immutable and it's done.

int[3] table = [6, 123, 0x87];

becomes:

immutable int[3] table = [6, 123, 0x87];

Immutability is also nice because it opens the door for further compiler optimizations.

Marking As Shared

Global data that is meant to be shared among multiple threads should be marked with the shared keyword:

shared int flag;

Not only does this cause flag to be put into classic global storage, it is also typed as being shared:

int* p = &flags;           // error, flags is shared
shared(int)* q = &flags;   // ok

The shared type attribute is transitive (like const and immutable) are. This enables static checking and sharing correctness.

Cowboying With __gshared

Sometimes, none of the above solutions will be acceptable:

  1. interfacing with C code that uses classic globals
  2. just get it working, and go back and fix it later
  3. the app is single threaded only, so no sharing issues
  4. you need every erg of performance
  5. you want to handle all the synchronization issues yourself

As D is a systems language, of course there's a way to do this. Use the storage class __gshared:

__gshared int x;

void main()
{
    __gshared int y;
}

__gshared stores the variable in the classic global data segment.

Naturally, __gshared is not allowed in safe mode.

Using __gshared makes such code easily searchable when doing QA code reviews or when going back later to fix any workarounds.

Compile Errors

The most common compiler error related to TLS will be:

int x;
int* p = &x;

test.d(2): Error: non-constant expression & x

While this works with classic global variables, it won't work with TLS variables. The reason is because TLS variables don't have a location in memory known to either the linker or the loader. It's a runtime computed value.

The solution is to initialize such things in a static constructor.

Link Errors

Sometimes you may encounter strange error messages from the linker about the global variables. These are nearly always caused by one module putting the variable in TLS, and another putting that same variable in classic global storage. This can happen when linking code with libraries that were built with earlier versions of dmd. Check that libphobos2.a was properly replaced with the latest. It can also happen when interfacing with C. C globals default to being classic global, although C does support TLS declarations. Make sure the corresponding D declarations match the C ones in terms of TLS or classic global.

int x;
extern int y;
__thread int z;

extern (C)
{
    extern shared int x;
    shared int y;
    extern int z;
}

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


Hijack

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Function Hijacking Mitigation

As software becomes more complex, we become more reliant on module interfaces. An application may import and combine modules from multiple sources, including sources from outside the company. The module developers must be able to maintain and improve those modules without inadvertently stepping on the behavior of modules over which they cannot have knowledge of. The application developer needs to be notified if any module changes would break the application. This talk covers function hijacking, where adding innocent and reasonable declarations in a module can wreak arbitrary havoc on an application program in C++ and Java. We'll then look at how modest language design changes can largely eliminate the problem in the D programming language.

Global Function Hijacking

Let's say we are developing an application that imports two modules: X from the XXX Corporation, and Y from the YYY Corporation. Modules X and Y are unrelated to each other, and are used for completely different purposes. The modules look like:

module X;

void foo();
void foo(long);

module Y;

void bar();

The application program would look like:

import X;
import Y;

void abc()
{
    foo(1);  // calls X.foo(long)
}

void def()
{
    bar();   // calls Y.bar();
}

So far, so good. The application is tested and works, and is shipped. Time goes by, the application programmer moves on, the application is put in maintenance mode. Meanwhile, YYY Corporation, responding to customer requests, adds a type A and a function foo(A):

module Y;

void bar();
class A;
void foo(A);

The application maintainer gets the latest version of Y, recompiles, and no problems. So far, so good. But then, YYY Corporation expands the functionality of foo(A), adding a function foo(int):

module Y;

void bar();
class A;
void foo(A);
void foo(int);

Now, our application maintainer routinely gets the latest version of Y, recompiles, and suddenly his application is doing something unexpected:

import X;
import Y;

void abc()
{
    foo(1);  // calls Y.foo(int) rather than X.foo(long)
}

void def()
{
    bar();   // calls Y.bar();
}

because Y.foo(int) is a better overloading match than X.foo(long). But since X.foo does something completely and totally different than Y.foo, the application now has a potentially very serious bug in it. Even worse, the compiler offers NO indication that this happened and cannot because, at least for C++, this is how the language is supposed to work.

In C++, some mitigation can be done by using namespaces or (hopefully) unique name prefixes within the modules X and Y. This doesn't help the application programmer, however, who probably has no control over X or Y.

The first stab at fixing this problem in the D programming language was to add the rules:

  1. by default functions can only overload against other functions in the same module
  2. if a name is found in more than one scope, in order to use it it must be fully qualified
  3. in order to overload functions from multiple modules together, an alias statement is used to merge the overloads

So now, when YYY Corporation added the foo(int) declaration, the application maintainer now gets a compilation error that foo is defined in both module X and module Y, and has an opportunity to fix it.

This solution worked, but is a little restrictive. After all, there's no way foo(A) would be confused with foo() or foo(long), so why have the compiler complain about it? The solution turned out to be to introduce the notion of overload sets.

Overload Sets

An overload set is formed by a group of functions with the same name declared in the same scope. In the module X example, the functions X.foo() and X.foo(long) form a single overload set. The functions Y.foo(A) and Y.foo(int) form another overload set. Our method for resolving a call to foo becomes:

  1. Perform overload resolution independently on each overload set
  2. If there is no match in any overload set, then error
  3. If there is a match in exactly one overload set, then go with that
  4. If there is a match in more than one overload set, then error

The most important thing about this is that even if there is a BETTER match in one overload set over another overload set, it is still an error. The overload sets must not overlap.

In our example:

void abc()
{
    foo(1);  // matches Y.foo(int) exactly, X.foo(long) with conversions
}

will generate an error, whereas:

void abc()
{
    A a;
    foo(a);  // matches Y.foo(A) exactly, nothing in X matches
    foo();   // matches X.foo() exactly, nothing in Y matches
}

compiles without error, as we'd intuitively expect.

If overloading of foo between X and Y is desired, the following can be done:

import X;
import Y;

alias X.foo foo;
alias Y.foo foo;

void abc()
{
    foo(1);  // calls Y.foo(int) rather than X.foo(long)
}

and no error is generated. The difference here is that the user deliberately combined the overload sets in X and Y, and so presumably both knows what he's doing and is willing to check the foo's when X or Y is updated.

Derived Class Member Function Hijacking

There are more cases of function hijacking. Imagine a class A coming from AAA Corporation:

module M;

class A { }

and in our application code, we derive from A and add a virtual member function foo:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.foo(1);   // calls B.foo(long)
}

and everything is hunky-dory. As before, things go on, AAA Corporation (who cannot know about B) extends A's functionality a bit by adding foo(int):

module M;

class A
{
    void foo(int);
}

Now, consider if we're using Java-style overloading rules, where base class member functions overload right alongside derived class functions. Now, our application call:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.foo(1);   // calls A.foo(int), AAAEEEEEIIIII!!!
}

and the call to B.foo(long) was hijacked by the base class A to call A.foo(int), which likely has no meaning whatsoever in common with B.foo(long). This is why I don't like Java overloading rules. C++ has the right idea here in that functions in a derived class hide all the functions of the same name in a base class, even if the functions in the base class might be a better match. D follows this rule. And once again, if the user desires them to be overloaded against each other, this can be accomplished in C++ with a using declaration, and in D with an analogous alias declaration.

Base Class Member Function Hijacking

I bet you suspected there was more to it than that, and you'd be right. Hijacking can go the other way, too. A derived class can hijack a base class member function!

Consider:

module M;

class A
{
    void def() { }
}

and in our application code, we derive from A and add a virtual member function foo:

import M;

class B : A
{
    void foo(long);
}

void abc(B b)
{
    b.def();   // calls A.def()
}

AAA Corporation once again knows nothing about B, and adds a function foo(long) and uses it to implement some needed new functionality of A:

module M;

class A
{
    void foo(long);

    void def()
    {
        foo(1L);   // expects to call A.foo(long)
    }
}

but, whoops, A.def() now calls B.foo(long). B.foo(long) has hijacked the A.foo(long). So, you might say, the designer of A should have had the foresight for this, and make foo(long) a non-virtual function. The problem is that A's designer may very easily have intended A.foo(long) to be virtual, as it's a new feature of A. He cannot have known about B.foo(long). Take this to the logical conclusion, and we realize that under this system of overriding, there is no safe way to add any functionality to A.

The D solution is straightforward. If a function in a derived class overrides a function in a base class, it must use the storage class override. If it overrides without using the override storage class it's an error. If it uses the override storage class without overriding anything, it's an error.

class C
{
    void foo();
    void bar();
}
class D : C
{
    override void foo();  // ok
    void bar();           // error, overrides C.bar()
    override void abc();  // error, no C.abc()
}

This eliminates the potential of a derived class member function hijacking a base class member function.

Derived Class Member Function Hijacking #2

There's one last case of base member function hijacking a derived member function. Consider:

module A;

class A
{
    void def()
    {
        foo(1);
    }

    void foo(long);
}

Here, foo(long) is a virtual function that provides a specific functionality. Our derived class designer overrides foo(long) to replace that behavior with one suited to the derived class' purpose:

import A;

class B : A
{
    override void foo(long);
}

void abc(B b)
{
    b.def();   // eventually calls B.foo(long)
}

So far, so good. The call to foo(1) inside A winds up correctly calling B.foo(long). Now A's designer decides to optimize things, and adds an overload for foo:

module A;

class A
{
    void def()
    {
    foo(1);
    }

    void foo(long);
    void foo(int);
}

Now,

import A;

class B : A
{
    override void foo(long);
}

void abc(B b)
{
    b.def();   // eventually calls A.foo(int)
}

Doh! B thought he was overriding the behavior of A's foo, but did not. B's programmer needs to add another function to B:

class B : A
{
    override void foo(long);
    override void foo(int);
}

to restore correct behavior. But there's no clue he needs to do that. Compile time is of no help at all, as the compilation of A has no knowledge of what B overrides.

Let's look at how A calls the virtual functions, which it does through the vtbl[]. A's vtbl[] looks like:

A.vtbl[0] = &A.foo(long);
A.vtbl[1] = &A.foo(int);

B's vtbl[] looks like:

B.vtbl[0] = &B.foo(long);
B.vtbl[1] = &A.foo(int);

and the call in A.def() to foo(int) is actually a call to vtbl[1]. We'd really like A.foo(int) to be inaccessible from a B object. The solution is to rewrite B's vtbl[] as:

B.vtbl[0] = &B.foo(long);
B.vtbl[1] = &error;

where, at runtime, an error function is called which will throw an exception. It isn't perfect since it isn't caught at compile time, but at least the application program won't blithely be calling the wrong function and continue on.

Update: A compile time warning is now generated whenever the vtbl[] gets an error entry.

Conclusion

Function hijacking is a pernicious and particularly nasty problem in complex C++ and Java programs because there is no defense against it for the application programmer. Some small modifications to the language semantics can defend against it without sacrificing any power or performance.

References

  • digitalmars.D - Hijacking
  • digitalmars.D - Re: Hijacking
  • digitalmars.D - aliasing base methods
  • Eiffel, Scala and C# use override or something analogous

Credits:

  • Kris Bell
  • Frank Benoit
  • Andrei Alexandrescu

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


Const and Immutable

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Const and Immutable

When examining a data structure or interface, it is very helpful to be able to easily tell which data can be expected to not change, which data might change, and who may change that data. This is done with the aid of the language typing system. Data can be marked as const or immutable, with the default being changeable (or mutable).

immutable applies to data that cannot change. Immutable data values, once constructed, remain the same for the duration of the program's execution. Immutable data can be placed in ROM (Read Only Memory) or in memory pages marked by the hardware as read only. Since immutable data does not change, it enables many opportunities for program optimization, and has applications in functional style programming.

const applies to data that cannot be changed by the const reference to that data. It may, however, be changed by another reference to that same data. Const finds applications in passing data through interfaces that promise not to modify them.

Both immutable and const are transitive, which means that any data reachable through an immutable reference is also immutable, and likewise for const.

Immutable Storage Class

The simplest immutable declarations use it as a storage class. It can be used to declare manifest constants.

immutable int x = 3;	// x is set to 3
x = 4;			// error, x is immutable
char[x] s;		// s is an array of 3 char's

The type can be inferred from the initializer:

immutable y = 4;	// y is of type int
y = 5;			// error, y is immutable

If the initializer is not present, the immutable can be initialized from the corresponding constructor:

immutable int z;
void test()
{
    z = 3;		// error, z is immutable
}
static this()
{
    z = 3;    // ok, can set immutable that doesn't have
              // static initializer
}

The initializer for a non-local immutable declaration must be evaluatable at compile time:

int foo(int f) { return f * 3; }
int i = 5;
immutable x = 3 * 4;      // ok, 12
immutable y = i + 1;      // error, cannot evaluate at compile time
immutable z = foo(2) + 1; // ok, foo(2) can be evaluated at compile time, 7

The initializer for a non-static local immutable declaration is evaluated at run time:

int foo(int f)
{
  immutable x = f + 1;  // evaluated at run time
  x = 3;                // error, x is immutable
}

Because immutable is transitive, data referred to by an immutable is also immutable:

immutable char[] s = "foo";
s[0] = 'a';  // error, s refers to immutable data
s = "bar";   // error, s is immutable

Immutable declarations can appear as lvalues, i.e. they can have their address taken, and occupy storage.

Const Storage Class

A const declaration is exactly like an immutable declaration, with the following differences:

  • Any data referenced by the const declaration cannot be changed from the const declaration, but it might be changed by other references to the same data.
  • The type of a const declaration is itself const.

Immutable Type

Data that will never change its value can be typed as immutable. The immutable keyword can be used as a type constructor:

immutable(char)[] s = "hello";

The immutable applies to the type within the following parentheses. So, while s can be assigned new values, the contents of s[] cannot be:

s[0] = 'b';  // error, s[] is immutable
s = null;    // ok, s itself is not immutable

Immutableness is transitive, meaning it applies to anything that can be referenced from the immutable type:

immutable(char*)** p = ...;
p = ...;        // ok, p is not immutable
*p = ...;       // ok, *p is not immutable
**p = ...;      // error, **p is immutable
***p = ...;     // error, ***p is immutable

Immutable used as a storage class is equivalent to using immutable as a type constructor for the entire type of a declaration:

immutable int x = 3;   // x is typed as immutable(int)
immutable(int) y = 3;  // y is immutable

Creating Immutable Data

The first way is to use a literal that is already immutable, such as string literals. String literals are always immutable.

auto s = "hello";   // s is immutable(char)[5]
char[] p = "world"; // error, cannot implicitly convert immutable
            // to mutable

The second way is to cast data to immutable. When doing so, it is up to the programmer to ensure that no other mutable references to the same data exist.

char[] s = ...;
immutable(char)[] p = cast(immutable)s;     // undefined behavior
immutable(char)[] p = cast(immutable)s.dup; // ok, unique reference

The .idup property is a convenient way to create an immutable copy of an array:

auto p = s.idup;
p[0] = ...;	  // error, p[] is immutable

Removing Immutable With A Cast

The immutable type can be removed with a cast:

immutable int* p = ...;
int* q = cast(int*)p;

This does not mean, however, that one can change the data:

*q = 3; // allowed by compiler, but result is undefined behavior

The ability to cast away immutable-correctness is necessary in some cases where the static typing is incorrect and not fixable, such as when referencing code in a library one cannot change. Casting is, as always, a blunt and effective instrument, and when using it to cast away immutable-correctness, one must assume the responsibility to ensure the immutableness of the data, as the compiler will no longer be able to statically do so.

Immutable Member Functions

Immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable. They are declared as:

struct S
{   int x;

    immutable void foo()
    {
    x = 4;	    // error, x is immutable
    this.x = 4; // error, x is immutable
    }

The const and immutable function attributes can also appear after the closing parenthesis of the parameter list:

struct S
{
    void bar() immutable
    {
    }
}

Const Type

Const types are like immutable types, except that const forms a read-only view of data. Other aliases to that same data may change it at any time.

Const Member Functions

Const member functions are functions that are not allowed to change any part of the object through the member function's this reference.

Implicit Conversions

Mutable and immutable types can be implicitly converted to const. Mutable types cannot be implicitly converted to immutable, and vice versa.

Comparing D Immutable and Const with C++ Const

Const, Immutable Comparison
Feature | D | C++98
const keyword | Yes | Yes
immutable keyword | Yes | No
const notation Functional:
//ptr to const ptr to const int
const(int*)* p;
Postfix:
//ptr to const ptr to const int
const int *const *p;
transitive const Yes:
//const ptr to const ptr to const int
const int** p;
**p = 3; // error
No:
// const ptr to ptr to int
int** const p;
**p = 3;    // ok
cast away const Yes:
// ptr to const int
const(int)* p;
int* q = cast(int*)p; // ok
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p; //ok
modification after casting away const No:
// ptr to const int
const(int)* p;
int* q = cast(int*)p;
*q = 3;   // undefined behavior
Yes:
// ptr to const int
const int* p;
int* q = const_cast<int*>p;
*q = 3;   // ok
overloading of top level const Yes:
void foo(int x);
void foo(const int x);  //ok
No:
void foo(int x);
void foo(const int x);  //error
aliasing of const with mutable Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
Yes:
void foo(const int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;
   bar(*x); // bar(4)
}
...
int i = 3;
foo(&i, &i);
aliasing of immutable with mutable No:
void foo(immutable int* x, int* y)
{
   bar(*x); // bar(3)
   *y = 4;  // undefined behavior
   bar(*x); // bar(??)
}
...
int i = 3;
foo(cast(immutable)&i, &i);
No immutables
type of string literal | immutable(char)[] | const char*
implicit conversion of string literal to non-const | not allowed | allowed, but deprecated

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


Memory Management

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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. Since arrays are passed by reference, not by value, 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] = c - (cast(char)'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] = c - (cast(char)'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 std.outofmemory;
import std.gc;

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

    p = std.c.stdlib.malloc(sz);
    if (!p)
        throw new OutOfMemoryException();
    std.gc.addRange(p, p + sz);
    return p;
    }

    delete(void* p)
    {
    if (p)
    {   std.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 std.outofmemory;

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

    static this()
    {   void *p;

    p = malloc(bufsize);
    if (!p)
        throw new OutOfMemoryException;
    std.gc.addRange(p, p + bufsize);
    buffer = p[0 .. bufsize];
    }

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

    new(size_t sz)
    {   void *p;

    p = &buffer[bufindex];
    bufindex += sz;
    if (bufindex > buffer.length)
        throw new OutOfMemory;
    return p;
    }

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

    static int mark()
    {
    return bufindex;
    }

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

void test()
{
    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
  • are allocated using new
  • use new with no arguments (constructor arguments are allowed)
  • 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 std.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.

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


Exception Safety

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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

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


Templates Revisited

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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
  string str = "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 string decimalDigit = "0123456789"[n..n+1];
}

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

string 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(string pattern)
{
  string[] regexMatch(string str)
  {
    string[] 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:
 *	string 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(string str) { return 0; }
}

/// Match if testFirst(str) and testSecond(str) match
template testUnion(alias testFirst, alias testSecond)
{
  int testUnion(string 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(string text)
{
  int testText(string 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(string 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(string term1, string term2)
{
  int testRange(string str)
  {
    if (str.length && str[0] >= term1[0]
                   && str[0] <= term2[0])
      return 1;
    return testFail;
  }
}

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

/// Match if str[0] is a word character
template testWordChar()
{
  int testWordChar(string 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(string pattern)
{
  static if (pattern.length > 0)
  {
    static if (isSpecial!(pattern))
      const string parseTextToken = "";
    else
      const string parseTextToken =
           pattern[0..1] ~ parseTextToken!(pattern[1..$]);
  }
  else
    const string parseTextToken="";
}

/**
 * Parses pattern[] up to and including terminator.
 * Returns:
 *	token[]	 	everything up to terminator.
 *	consumed	number of characters in pattern[] parsed
 */
template parseUntil(string pattern,char terminator,bool fuzzy=false)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == '\\')
    {
      static if (pattern.length > 1)
      {
        const string nextSlice = pattern[2 .. $];
        alias parseUntil!(nextSlice,terminator,fuzzy) next;
        const string 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 string token="";
      const uint consumed = 1;
    }
    else
    {
      const string nextSlice = pattern[1 .. $];
      alias parseUntil!(nextSlice,terminator,fuzzy) next;
      const string token = pattern[0..1] ~ next.token;
      const uint consumed = next.consumed+1;
    }
  }
  else static if (fuzzy)
  {
    const string 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(string 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 string 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 string remaining = pattern[1 .. $];
      }
    }
    else
    {
      alias testChar!(pattern[0..1]) termFn;
      const uint thisConsumed = 1;
      const string 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,string 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(string 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, string 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(string 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(string pattern)
{
  static if (pattern.length > 0)
  {
    static if (pattern[0] == '[')
    {
      const string charClassToken =
          parseUntil!(pattern[1 .. $],']').token;
      alias regexCompileCharClass!(charClassToken) charClass;
      const string token = pattern[0 .. charClass.consumed+2];
      const string next = pattern[charClass.consumed+2 .. $];
      alias charClass.fn test;
    }
    else static if (pattern[0] == '\\')
    {
      alias regexCompileEscape!(pattern[1..pattern.length]) escapeSequence;
      const string token = pattern[0 .. escapeSequence.consumed+1];
      const string next =
          pattern[escapeSequence.consumed+1 .. $];
      alias escapeSequence.fn test;
    }
    else
    {
      const string token = parseTextToken!(pattern);
      static assert(token.length > 0);
      const string next = pattern[token.length .. $];
      alias testText!(token) test;
    }

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

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

template regexCompileRecurse(alias term,string 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(string 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.

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


Regular Expressions

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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.

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


LazyEvaluationOfFunctionArguments

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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 .

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


Variadic Templates

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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

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


Tuples

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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.

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


Mixins

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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.

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


SafeD

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

SafeD—The Safe Subset of D

by Bartosz Milewski, a member of the D design team

I've seen some very good programmers move away from C++ in favor of languages like Java or C#. Being a hard-core C++ programmer myself, I wondered why anyone would want to switch to a less powerful and less efficient language. Mind you, I could understand why a newcomer would opt for a simpler, flatter-learning-curve language but, once somebody invested the time and effort to become proficient in C++, why in the world would they want to abandon it?

The universal reason I've heard from the turncoats was “productivity.” The consensus seems to be that programmers are more productive using Java, C#, Ruby, or Python then they are using C++.

What are the major impediments to productive programming in C++?

Horrible syntax is one. This is actually more serious than it sounds. A good programmer can probably master some pretty horrible syntaxes given enough time. The problem is that C++ syntax and grammar is not only human-unfriendly but also parser-hostile. The fact that the Java market is saturated with productivity boosting tools is the reflection of the language's parseability. I have to yet see a C++ programming environment that would offer such powerful refactoring tools as are commonplace in Java.

Language safety is the other major factor. C++ is notorious for presenting a never ending gallery of opportunities to shoot yourself in the foot. In fact C++ not only provides the opportunity to write dangerous code, it encourages it. At some point a major C++ compiler vendor marked a portion of STL algorithms as "deprecated" because of safety concerns. In particular the C++ Standard Library, in accordance with the spirit of C++, extends the number of ways a buffer overflow bug might sneak into your program.

One notorious example is the std::swap_ranges algorithm, which takes three iterators. The first two iterators are supposed to delimit one range, the third one marks the beginning of the second range. No testing is done whether the second range doesn't extend past the end of the container. When it does, virus writers rejoice!

The pipe dream of programming language designers is to be able to guarantee that if a program compiles successfully, it will work. Of course you have to be reasonable about your definition of a "working" program. For instance, you might require that the program will never get "stuck"—a term which has a precise meaning in computer science, but loosely means that the program will not GP-fault on you (it is stuck in the sense that there is no well-defined system-independent next step). Languages that have such a property are called "sound".

Guess what, there is a well-defined (and meaningful) subset of Java that is sound. Real-life Java programs, for practical reasons, stray outside of this sound subset; but at least the use of unsafe features is less prevalent and easier to spot in a Java program than it is in a C++ program. In practice, a Java compiler will detect more bugs in your program than a C++ compiler, and that translates directly into less time spent debugging—ergo, higher productivity.

So what are the good features of C++?

Performance is one. It's really hard to beat C++ performance. If your program has to be fast and responsive you have little choice but to write it in C++ (or, in rare cases, in C or assembly).

Then there are the low-level features of C++ that let you write programs interacting directly with hardware. For instance, C and C++ are still kings of embedded programming.

C++ offers powerful abstractions, in particular the ability to write generic code. Java and C# have their own generics but they are feeble compared to what C++ has to offer.

All these features make C++ an ideal language for writing operating systems. Operating systems are huge programs that have to be fast and interact directly with hardware. But even outside operating systems there are a lot of applications that have to be large and fast.

So it looks like the programming world could be nicely partitioned between C++, Java, C# and the likes. And it all makes sense as long as you believe in the unavoidability of tradeoffs. But there is no law of nature that says, You have to trade productivity for power.

What about a language that is built like an onion. It has a reasonably simple and safe core, which is not unlike Java or C#. A programmer can quickly master a safe subset of it and be as productive as a Java programmer (if not more). And what if the safe subset offered performance that was comparable to C++?

And then, the same language has outer layers that can be mastered gradually, as the need arises. It offers low-level features to grind the hardware, and high-level features to generate code on demand. It offers modularity and implementation hiding. It has unrivaled compile time features that enable lightning fast runtime performance.

I'll let you in on a secret, this language is D.

Programming Pitfalls

Did you know that the famous "Hello World!" program, which is usually the first program people write in C, exposes some of the most dangerous features of the language? It contains this statement:

printf ("Hello World!\n");
Consider the signature of printf:
int printf (const char * restrict format, ...);

(restrict is a new C keyword.) First of all, it's a function that takes a variable number of arguments. The number and the types of arguments are encoded in the format string.

When is the match between the format and the argument list checked? Not at compile time—the compiler has no understanding of the format string (although some compilers may issue warnings if the string is statically known). At runtime then? Well, guess again. Consider this: If the programmer makes a mistake of calling printf with too few arguments, he or she will not get a nice error code or exception. Here's what the C Standard says about this situation:

If there are insufficient arguments for the format, the behavior is undefined.

Undefined behavior is the worst thing that may happen to a program. If you're lucky, the program will fault and terminate without prejudice. If you're not so lucky, the program will continue in a compromised state and, in the worst case, it will execute malicious code that will take over your computer.

The second dangerous feature of printf is its use of a pointer. It is up to the diligence of the programmer to ensure that a pointer points to a valid piece of data. In the "Hello World!" example, the pointer points to a null-terminated static string, so we're fine. But the following program will compile too:

char * format = 0;
printf (format);

Guess what happens. Inside printf the pointer is dereferenced and then all bets are off. Again, citing the C Standard,

If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

Let's talk about pointers some more. Every memory allocation returns a valid pointer (unless the program runs out of memory). You might think that dereferencing such a pointer would be safe. That is correct as long as your program doesn't free the allocated memory thus ending the lifetime of the object. After that, you are dealing with a dangling pointer and all bets are off. Again, C Standard is pretty upfront about it.

Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.

As you can see, C was not designed for the faint of heart. It's a low-level language and the programmer better know what he or she is doing or suffer the consequences.

C++ is different though, right?

Throughout its history, C++ has been struggling with C legacy. A lot of constructs have been provided to patch the unsafe features of C. For instance, the "Hello World!" program in C++ might be transformed to a safer version.

std:cout << "Hello World!" << std::endl;

There is no variable argument count, and the std::cout object is smart enough to understand the types of arguments passed to it (still, many programmers continue using printf in C++, if only for its syntactic simplicity).

Unlike in C, memory allocation in C++ is typed and combined with object construction (as long as you stay away from malloc and free). That's the good part. However, objects still have to be explicitly recycled (deleted). And after recycling, the program is still left with dangling pointers, whose dereferencing—you guessed it—leads to undefined behavior.

Whereas pointers were important in C, C++ embraced them as the main vehicle for the Standard Library. STL algorithms use iterators, objects that are either pointers themselves or imitate the behavior (and the pitfalls) of pointers. Just like with pointers, a programmer's error in using iterators leads to undefined behavior (see the swap_range example).

In response to C/C++'s inherent lack of safety, languages like Java and C# took a different path. They either ban pointers altogether or relegate them to special "unsafe" blocks. Memory management, with its risk of accessing recycled data, is taken away from the programmer and dealt with by automatic garbage collection. There are many other simplifications and safety improvements over C++. Unfortunately they all come at the expense of expressive power and performance.

The SafeD Subset

In D, we expect the vast majority of programmers to operate within the safe subset of D, which we call SafeD. The safety and the ease of use of SafeD is comparable to Java—in fact Java programs can be machine-translated into this safe subset of D. SafeD is easy to learn and it keeps the programmers away from undefined behaviors. It is also very efficient.

When you enter SafeD, you leave your pointers, unchecked casts and unions at the door. Memory management is provided to you courtesy of Garbage Collection. Class objects are passed around using opaque handles. Arrays and strings are bound-checked (it's possible to turn the checks off with a compiler switch, but then you're no longer in SafeD). You may still write code that will throw a runtime exception (e.g., array out-of-bounds error, or uninitialized-class-object error), but you won't be able to overwrite memory that hasn't been allocated to you or that has already been recycled.

Let's look at the "Hello World!" program in D. On the face of it, it's not much different than its C counterpart:

writeln ("Hello Safe World!");

The function writeln is the equivalent of the C printf (more precisely, it's the representative of a family of output functions including write and its formatting versions, writef and writefln). Just like printf, writeln accepts a variable number of arguments of arbitrary types. But here the similarity ends. As long as you pass SafeD-arguments to writeln, you are guaranteed not to encounter any undefined behavior. Here, writeln is called with a single argument of the type string. In contrast to C, D string is not a pointer. It is an array of immutable char, and arrays are a built into the safe subset of D.

You might be interested to know how the safety of writeln is accomplished in D. One possible approach would have been to make writeln a compiler intrinsic, so that correct code would be generated on a case-by-case basis. The beauty of D is that it gives a sophisticated programmer tools that allow such case-by-case code generation of code. The advanced features used in the implementation of writeln are:

  • Compile-time code generation using templates, and
  • A safe mechanism for dealing with variable number of arguments using tuples.

SafeD Libraries

One of the major differences between Java and D is that D has enough power to let an advanced programmer implement libraries that can be used within SafeD.

A lot of advanced features of D are compatible with SafeD, as long as they don't force the user to use unsafe types. For instance, a library may provide the implementation of a generic list. The list can be instantiated with any type, in particular with a pointer type. A list of pointers, by definition, cannot be safe, because pointer arithmetic is unsound. However, a list of ints or class objects can and should be safe. That's why such ageneric lists can be used in SafeD, even though their usage outside of SafeD may be unsafe.

Moreover, it might be more efficient to base the internal implementation of a list on pointers. As long as these pointers are not exposed to the client, such an implementation might be certified to be SafeD compatible1 . You can have a cake (advanced features of D) and eat it too (take advantage of them in SafeD).

One User's Experience

Even before I came up with the idea of SafeD2, I tried to restrict myself to the safe subset of D for most of my projects. I was surprised how much could be accomplished and how my productivity soared. I also showed SafeD to my co-worker, a C++ programmer, and he was able to learn it in a very short time.

So far my experience has been that if a SafeD program compiles without errors then, in a vast majority of cases, it runs without errors, and does what I want it to do. That definitely hasn't been my experience with C++.

What is even more surprising to me is that I was able to accomplish all that with almost non-existing support from tools and with a compiler that excels in cryptic error messages. D is still lacking a lot of infrastructure, but I can imagine how easy programming will be when a critical mass of productivity tools sprouts around it. And unlike C++, D is easy to parse and its front end is open source. So there are no barriers to entry for tool writers.

Footnotes

  1. There is no central authority to issue such certifications, each library provider has to establish a level of trust with its clients. In particular, you should expect the D standard library to be SafeD certified by the compiler provider.
  2. The name, SafeD, was proposed by David B. Held.

Acknowledgments

Many thanks go to the rest of the D design team for valuable feedback and corrections to this article

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


DMD Compiler for Linux

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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 Linux operating system (will work on 64 bit Linux)
  3. Gnu C compiler (gcc)

Files

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/linux/bin/dmd
D compiler executable
dmd2/linux/bin/dumpobj
Elf file dumper
dmd2/linux/bin/obj2asm
Elf file disassembler
dmd2/linux/bin/shell
Simple command line shell
dmd2/linux/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/linux/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.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 dmd2/linux/bin/dmd.conf /etc
  • Put dmd2/linux/bin on your PATH, or copy the linux executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp dmd2/linux/lib/libphobos2.a /usr/lib

    • Installing dmd on 64 bit Linux

    Since dmd is a 32 bit compiler, the 32 bit gnu libraries must be installed:

    sudo apt-get install gcc-multilib g++-multilib libc6-i386 libc6-dev-i386

    The ia32-libs package has more 32 bit libraries, and may optionally also be installed:

    sudo apt-get install ia32-libs

    If you are using the .deb package for one-click install, it may give you an error about it being only for i386. To force it to install:

    sudo dpkg -i --force-architecture dmd_X.XXX-0_i386.deb

    where X.XXX is the version number of the package.

    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 libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.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
    -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
    -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.
    -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
    -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.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -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 and asserts. Array bounds checking is not done for system and trusted functions.
    -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.
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -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)

    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 -I%@P%/../src/druntime/import

    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 ~/dmd2/src/dmd
make -f linux.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/linux/bin/dmd
cd ../phobos
make -f linux.mak DMD=~/dmd2/linux/bin/dmd

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


DMD Compiler for FreeBSD

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/freebsd/bin/dmd
D compiler executable
dmd2/freebsd/bin/dumpobj
Elf file dumper
dmd2/freebsd/bin/obj2asm
Elf file disassembler
dmd2/freebsd/bin/shell
Simple command line shell
dmd2/freebsd/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/freebsd/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.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 dmd2/freebsd/bin/dmd.conf /etc
  • Put dmd2/freebsd/bin on your PATH, or copy the FreeBSD executables to /usr/local/bin
  • Copy the library to /usr/lib:
    cp dmd2/freebsd/lib/libphobos2.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 libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.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
    -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
    -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.
    -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
    -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.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, x-www-browser is assumed.
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -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 and asserts. Array bounds checking is not done for system and trusted functions.
    -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.
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -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)

    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 -I%@P%/../src/druntime/import

    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 ~/dmd2/src/dmd
make -f freebsd.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/freebsd/bin/dmd
cd ../phobos
make -f freebsd.mak DMD=~/dmd2/freebsd/bin/dmd

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


DMD Compiler for OSX

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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

dmd2/src/phobos/
D runtime library source
dmd2/src/dmd/
D compiler front end source under dual (GPL and Artistic) license
dmd2/html/d/
Documentation
dmd2/samples/d/
Sample D programs
dmd2/osx/bin/dmd
D compiler executable
dmd2/osx/bin/dumpobj
Mach-O file dumper
dmd2/osx/bin/obj2asm
Mach-O file disassembler
dmd2/osx/bin/shell
Simple command line shell
dmd2/osx/bin/dmd.conf
Global compiler settings (copy to /etc/dmd.conf)
dmd2/osx/lib/libphobos2.a
D runtime library (copy to /usr/lib/libphobos2.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 ~/dmd2 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:
    dmd2/osx/bin/dmd hello
./hello
    and it should print:
    hello world!
  • To install a global copy:
  • Copy binaries to /usr/local/bin:
    sudo cp dmd2/osx/bin/{dmd,dumpobj,obj2asm,shell,rdmd} /usr/local/bin
sudo cp dmd2/osx/bin/dmdx.conf /usr/local/bin/dmd.conf
  • Copy the library to /usr/lib:
    sudo cp dmd2/osx/lib/libphobos2.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 libphobos2.a
    -defaultlib=libname
    link in libname as the default library when not compiling for symbolic debugging instead of libphobos2.a
    -deps=filename
    write module dependencies as text to filename
    -dylib
    generate dylib library
    -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
    -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
    -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.
    -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
    -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.
    -man
    open browser specified by the BROWSER environment variable on this page. If BROWSER is undefined, Safari is assumed.
    -noboundscheck
    turns off all array bounds checking, even for safe functions
    -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 and asserts. Array bounds checking is not done for system and trusted functions.
    -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.
    -unittest
    compile in unittest code, turns on asserts, and sets the unittest version identifier
    -v
    verbose
    -vtls
    print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
    -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)

    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 -I%@P%/../src/druntime/import

    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 ~/dmd2/src/dmd
make -f osx.mak

    Compiling Phobos

    Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

    cd ~/dmd2/src/druntime
make -f posix.mak DMD=~/dmd2/osx/bin/dmd
cd ../phobos
make -f osx.mak DMD=~/dmd2/osx/bin/dmd

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


DMD Compiler for Windows

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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

\dmd2\src\phobos\
D runtime library source
\dmd2\src\dmd\
D compiler front end source under dual (GPL and Artistic) license
\dmd2\html\d\
Documentation
\dmd2\samples\d\
Sample D programs
\dmd2\windows\bin\dmd.exe
D compiler executable
\dmd2\windows\bin\shell.exe
Simple command line shell
\dmd2\windows\bin\sc.ini
Global compiler settings
\dmd2\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 \dmd2 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:

\dmd2\windows\bin\shell all.sh

in the \dmd2\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 \dmd2\bin\windbg
-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
-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.
-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
-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
-noboundscheck
turns off all array bounds checking, even for safe functions
-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 and asserts. Array bounds checking is not done for system and trusted functions.
-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
-vtls
print informational messages identifying variables defaulting to thread local storage. Handy for migrating to shared model.
-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)

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=\dmd2\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=\dmd2\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" "-I%@P%\..\src\druntime\import"
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:\dmd2\bin\sc.ini, then %@P% will be replaced with c:\dmd2\bin, and the above sc.ini will be interpreted as:

[Environment]
LIB="c:\dmd2\bin\..\lib";\dm\lib

DFLAGS="-Ic:\dmd2\bin\..\src\phobos" "-Ic:\dmd2\bin\..\src\druntime\import"
LINKCMD="c:\dmd2\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 \dmd2\src\dmd
make -f win32.mak

Compiling Phobos

Complete source code is provided to build Phobos, the D runtime library. Follow these steps:

cd \dmd2\src\druntime
make -f win32.mak DMD=\dmd2\windows\bin\dmd
cd ..\phobos
make -f win32.mak DMD=\dmd2\windows\bin\dmd

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


Code Coverage Analysis

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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

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


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

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

Debugging D on Windows

The Microsoft Windows debugger \dmd2\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 \dmd2\windows\bin\windbg.hlp.

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


htod

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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.

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


Glossary

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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.
Data Race
One thread reading or writing a memory location while another thread is reading or writing that same location.
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.
Input range
A type (i.e., a struct or a class) that defines the member functions empty, head, and next. Input ranges are assumed to be strictly one-pass: there is no way to save the state of the iteration in a copy of the range. See also range.
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.

opApply
A special member function used to iterate over a collection; this is used by the ForeachStatement.
opApplyReverse
A special member function used to iterate over a collection in the reverse order; this is used by the ForeachStatement.
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.
Sequential Consistency
Data being written in one order in one thread being visible in the same order to another thread.
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.
TLS (Thread Local Storage)
TLS allocates each thread its own instance of the global data. See also Wikipedia.
UB (Undefined Behavior)
Undefined behavior happens when an illegal code construct is executed. Undefined behavior can include random, erratic results, crashes, faulting, etc. A buffer overflow is an example of undefined behavior.

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


ASCII Table

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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

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


Acknowledgements

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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

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


Lexical

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

Lexical

In D, 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 D lexical 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++.

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. Special token sequences 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.

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: white space, end of lines, comments, special token sequences, tokens, all followed by end of file.

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.

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:
    /* Characters */
    // Characters EndOfLine
    NestingBlockComment

Characters:
    Character
    Character Characters

NestingBlockComment:
    /+ NestingBlockCommentCharacters +/

NestingBlockCommentCharacters:
    NestingBlockCommentCharacter
    NestingBlockCommentCharacter NestingBlockCommentCharacters

NestingBlockCommentCharacter:
    Character
    NestingBlockComment
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 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:
    IdentiferStart
    IdentiferStart IdentifierChars

IdentifierChars:
    IdentiferChar
    IdentiferChar IdentifierChars

IdentifierStart:
    _
    Letter
    UniversalAlpha

IdentifierChar:
    IdentiferStart
    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

    HexString
    DelimitedString
    TokenString

WysiwygString:
    r" WysiwygCharacters " Postfixopt

AlternateWysiwygString:
    ` WysiwygCharacters ` Postfixopt

WysiwygCharacters:
    WysiwygCharacter
    WysiwygCharacter WysiwygCharacters

WysiwygCharacter:
    Character
    EndOfLine

DoubleQuotedString:
    " DoubleQuotedCharacters " Postfixopt

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 " Postfixopt

HexStringChars:
    HexStringChar
    HexStringChar HexStringChars

HexStringChar:
    HexDigit
    WhiteSpace
    EndOfLine

Postfix:
    c
    w
    d

DelimitedString:
    q" Delimiter WysiwygCharacters MatchingDelimiter "

TokenString:
    q{ Tokens }

A string literal is either a double quoted string, a wysiwyg quoted string, an escape sequence, a delimited string, a token string, or a hex string.

Wysiwyg Strings

Wysiwyg quoted strings are enclosed by r" and ". All characters between the r" and " are part of the string except for EndOfLine which is regarded as a single \n character. 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. EndOfLine is regarded as a single \n character.
"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

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 Postfix 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
c | char[ ]
w | wchar[ ]
d | dchar[ ]
"hello"c          // char[]
"hello"w          // wchar[]
"hello"d          // dchar[]

String literals are read only. Writes to string literals cannot always be detected, but cause undefined behavior.

Delimited Strings

Delimited strings use various forms of delimiters. The delimiter, whether a character or identifer, must immediately follow the " without any intervening whitespace. The terminating delimiter must immediately precede the closing " without any intervening whitespace. A nesting delimiter nests, and is one of the following characters:

Nesting Delimiters
Delimiter | Matching Delimiter
[ | ]
( | )
< | >
{ | }
q"(foo(xxx))"   // "foo(xxx)"
q"[foo{]"       // "foo{"

If the delimiter is an identifier, the identifier must be immediately followed by a newline, and the matching delimiter is the same identifier starting at the beginning of the line:

writefln(q"EOS
This
is a multi-line
heredoc string
EOS"
);

The newline following the opening identifier is not part of the string, but the last newline before the closing identifier is part of the string.

Otherwise, the matching delimiter is the same as the delimiter character:

q"/foo]/"       // "foo]"
q"/abc/def/"    // error

Token Strings

Token strings open with the characters q{ and close with the token }. In between must be valid D tokens. The { and } tokens nest. The string is formed of all the characters between the opening and closing of the token string, including comments.

q{foo}               // "foo"
q{/*}*/ }            // "/*}*/ "
q{ foo(q{hello}); }  // " foo(q{hello}); "
q{ @ }               // error, @ is not a valid D token
q{ __TIME__ }        // " __TIME__ ", i.e. it is not replaced with the time
q{ __EOF__ }         // error, as __EOF__ is not a token, it's end of file

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:
    Decimal
    Binary
    Octal
    Hexadecimal

IntegerSuffix:
    L
    u
    U
    Lu
    LU
    uL
    UL

Decimal:
    0
    NonZeroDigit
    NonZeroDigit DecimalDigits

Binary:
    0b BinaryDigits
    0B BinaryDigits

Octal:
    0 OctalDigits

Hexadecimal:
    0x HexDigits
    0X HexDigits

NonZeroDigit:
    1
    2
    3
    4
    5
    6
    7
    8
    9

DecimalDigits:
    DecimalDigit
    DecimalDigit DecimalDigits

DecimalDigit:
    0
    NonZeroDigit
    _

BinaryDigits:
    BinaryDigit
    BinaryDigit BinaryDigits

BinaryDigit:
    0
    1
    _

OctalDigits:
    OctalDigit
    OctalDigit OctalDigits

OctalDigit:
    0
    1
    2
    3
    4
    5
    6
    7
    _

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigit:
    DecimalDigit
    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 ‘u’ or both.

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 . DecimalDigits DecimalExponent
    . Decimal
    . Decimal DecimalExponent
    LeadingDecimal DecimalExponent

DecimalExponent
    e DecimalDigits
    E DecimalDigits
    e+ DecimalDigits
    E+ DecimalDigits
    e- DecimalDigits
    E- DecimalDigits

HexFloat:
    HexPrefix HexDigits . HexDigits HexExponent
    HexPrefix . HexDigits HexExponent
    HexPrefix HexDigits HexExponent

HexPrefix:
    0x
    0X

HexExponent:
    p DecimalDigits
    P DecimalDigits
    p+ DecimalDigits
    P+ DecimalDigits
    p- DecimalDigits
    P- DecimalDigits

Suffix:
    FloatSuffix
    RealSuffix
    ImaginarySuffix
    FloatSuffix ImaginarySuffix
    RealSuffix ImaginarySuffix

FloatSuffix:
    f
    F

RealSuffix:
    L

ImaginarySuffix:
    i

LeadingDecimal:
    Decimal
    0 DecimalDigits
Floats can be in decimal or hexadecimal format, as in standard C.

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 in the semantic analysis:

4.5 + 6.2i		// complex number

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
    immutable
    import
    in
    inout
    int
    interface
    invariant
    ireal
    is

    lazy
    long

    macro
    mixin
    module

    new
    nothrow
    null

    out
    override

    package
    pragma
    private
    protected
    public
    pure

    real
    ref
    return

    scope
    shared
    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

    __FILE__
    __LINE__
    __gshared
    __thread
    __traits

Special Tokens

These tokens are replaced with other tokens according to the following table:

Special Tokens
Special Token | Replaced with...
__DATE__ | string literal of the date of compilation "mmm dd yyyy"
__EOF__ | sets the scanner to the end of the file
__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

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.

SpecialTokenSequence:
    # line Integer EndOfLine
    # line Integer Filespec EndOfLine

Filespec:
    " Characters "
This sets the source line number to Integer, 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.

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


Modules

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

Modules

Module:
    ModuleDeclaration DeclDefs
    DeclDefs

DeclDefs:
    DeclDef
    DeclDef DeclDefs

DeclDef:
    AttributeSpecifier
    ImportDeclaration
    EnumDeclaration
    ClassDeclaration
    InterfaceDeclaration
    AggregateDeclaration
    Declaration
    Constructor
    Destructor
    UnitTest
    StaticConstructor
    StaticDestructor
    SharedStaticConstructor
    SharedStaticDestructor
    ConditionalDeclaration
    StaticAssert
    TemplateDeclaration
    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

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.

Static constructors and static destructors run on thread local data, and are run whenever threads are created or destroyed.

Shared static constructors and shared static destructors are run on global shared data, and constructors are run once on program startup and destructors are run once on program termination.

Order of Static Construction

Shared static constructors on all modules are run before any static constructors.

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.

Shared static destructors are executed after static destructors.

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.

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


Declarations

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Tue Dec 7 01:17:16 2010

Declarations

Declaration:
        alias Decl
        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
        const( type )
        immutable( type )
        shared( type )
        inout( type )

BasicTypeX:
        bool
        byte
        ubyte
        short
        ushort
        int
        uint
        long
        ulong
        char
        wchar
        dchar
        float
        double
        real
        ifloat
        idouble
        ireal
        cfloat
        cdouble
        creal
        void

BasicType2:
        *
        [ ]
        [ AssignExpression ]
        [ AssignExpression .. AssignExpression ]
        [ Type ]
        delegate Parameters FunctionAttributesopt
        function Parameters FunctionAttributesopt

Declarator:
        BasicType2opt ( Declarator ) DeclaratorSuffixesopt
        BasicType2opt Identifier DeclaratorSuffixesopt

DeclaratorSuffixes:
        DeclaratorSuffix
        DeclaratorSuffix DeclaratorSuffixes

DeclaratorSuffix:
        [ ]
        [ AssignExpression ]
        [ Type ]
    TemplateParameterListopt Parameters MemberFunctionAttributesopt Constraintopt

IdentifierList:
        Identifier
        Identifier . IdentifierList
        TemplateInstance
        TemplateInstance . IdentifierList

StorageClasses:
    StorageClass
    StorageClass StorageClasses

StorageClass:
        abstract
        auto
        const
        deprecated
        extern
        final
        immutable
        inout
        shared
    nothrow
        override
    pure
    __gshared
    Property
        scope
        static
        synchronized

Property:
    @ Identifier

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
        immutable
        in
        inout
        lazy
        out
        ref
        scope
        shared

FunctionAttributes:
    FunctionAttribute
    FunctionAttribute FunctionAttributes

FunctionAttribute:
    nothrow
    pure
    Property

MemberFunctionAttributes:
    MemberFunctionAttribute
    MemberFunctionAttribute MemberFunctionAttributes

MemberFunctionAttribute:
    const
    immutable
    inout
    shared
    FunctionAttribute

DefaultInitializerExpression:
    AssignExpression
        __FILE__
    __LINE__

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 deprecated:

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 immutable(char)[]

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.

An ArrayLiteral is inferred to be a dynamic array type rather than a static array:

auto v = ["hello", "world"];   // type is string[], not string[2]

Type Aliasing

It's sometimes convenient to use an alias for a type, such as a shorthand for typing out a long, complex type like a pointer to a function. In D, this is done with the alias declaration:

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

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 three 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.
  3. typeof(return) will, when inside a function scope, give the return type of that 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.

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


Types

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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

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

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 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:

enum Foo { E }
Foo f;
i = f;			// OK
f = i;			// error
f = cast(Foo)i;		// OK
f = 0;                  // error
f = 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 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 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 and the other is the base type of that enum, the result is the base type.
  3. If the two operands are different 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(ulong)-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 function pointer. 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)

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


Properties

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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_normal | 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. 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.a.init	// is 0
Foo.b.init	// 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:

struct Foo { }

enum Enum { RED }

typedef int myint;

void main()
{
    writefln((1+2).stringof);       // "1 + 2"
    writefln(Foo.stringof);         // "Foo"
    writefln(test.Foo.stringof);    // "test.Foo"
    writefln(int.stringof);         // "int"
    writefln((int*[5][]).stringof); // "int*[5][]"
    writefln(Enum.RED.stringof);    // "Enum.RED"
    writefln(test.myint.stringof);  // "test.myint"
    writefln((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.TypeInfo_Class.

User Defined Class and Struct Properties

Properties are member functions that can be syntactically treated as if they were fields. Properties can be read from or written to. A property is read by calling a method with no arguments; a property is written by calling a method with its argument being the value it is set to.

A simple property would be:

struct Foo
{
    @property int data() { return m_data; }	// read property

    @property int data(int value) { return m_data = value; } // write property

  private:
    int m_data;
}

Properties are marked with the @property attribute. Properties may only have zero or one parameter, and may not be variadic. Property functions may not be overloaded with non-property functions.

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, have their address taken, etc.

Note: Properties currently cannot be the lvalue of an op=, ++, or -- operator.

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


Attributes

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

Attributes

AttributeSpecifier:
    Attribute :
    Attribute DeclarationBlock

Attribute:
    LinkageAttribute
    AlignAttribute
    Pragma
    deprecated
    ProtectionAttribute
    static
    final
    synchronized
    override
    abstract
    const
    auto
    scope
    __gshared
    shared
    immutable
    inout
    @disable

DeclarationBlock:
    DeclDef
    { }
    { DeclDefs }

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;
    ...
}

For attributes with an optional else clause:

attribute
    declaration;
else
    declaration;

attribute			// affects all declarations in the block
{
    declaration;
    declaration;
    ...
}
else
{
    declaration;
    declaration;
    ...
}

Linkage Attribute

LinkageAttribute:
    extern
    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 is the ‘this’ object for the member function call. 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.

Const Attribute

const

The const attribute declares constants that can be evaluated at compile time. For example:

const int foo = 7;

const
{
    double bar = foo + 6;
}

immutable Attribute

__gshared Attribute

shared Attribute

inout Attribute

@disable Attribute

A reference to a declaration marked with the @disable attribute causes a compile time error. This can be used to explicitly disallow certain operations or overloads at compile time rather than relying on generating a runtime error.

struct T
{
    @disable this(this) { }   // disabling this makes T not copyable
}

struct S
{
    T t;        // uncopyable member makes S also not copyable
}

@disable void foo() { }

void main()
{
    S s;
    S t = s;    // error, S is not copyable
    foo();      // error, foo is disabled
}

Override Attribute

override

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

static

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

auto

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

scope

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.’

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


Pragmas

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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 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");
startaddress
Puts a directive into the object file saying that the function specified in the first argument will be the start address for the program:
void foo() { ... }
pragma(startaddress, foo);
This is not normally used for application level programming, but is for specialized systems work. For applications code, the start address is taken care of by the runtime library.

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) { ... }
}

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


Expressions

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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:

OrExpression, XorExpression, AndExpression, CmpExpression, ShiftExpression, AddExpression, CatExpression, MulExpression, PowExpression, CommaExpression, OrOrExpression, AndAndExpression

The following binary expressions are evaluated in an implementation-defined order:

AssignExpression, 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:
    AssignExpression
    AssignExpression , Expression
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
    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 = a op b
except that operand a is only evaluated once.

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
    CmpExpression
    AndAndExpression && CmpExpression

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:
    ShiftExpression
    AndExpression & ShiftExpression
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
    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.

The !in expression is the logical negation of the in operation.

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 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

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:
    PowExpression
    & UnaryExpression
    ++ UnaryExpression
    -- UnaryExpression
    * UnaryExpression
    - UnaryExpression
    + UnaryExpression
    ! UnaryExpression
    ~ UnaryExpression
    ( Type ) . Identifier
    NewExpression
    DeleteExpression
    CastExpression
    NewAnonClassExpression

New Expressions

NewExpression:
    NewArguments Type [ AssignExpression ]
    NewArguments Type ( ArgumentList )
    NewArguments Type
    NewArguments ClassArguments BaseClasslistopt { DeclDefs }

NewArguments:
    new ( ArgumentList )
    new ( )
    new

ClassArguments:
    class ( ArgumentList )
    class ( )
    class

ArgumentList:
    AssignExpression
        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.

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 ( CastParam ) UnaryExpression

CastParam:
        Type
    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 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)

Pow Expressions

PowExpression:
    PostfixExpression
    PostfixExpression ^^ UnaryExpression

PowExpression raises its left operand to the power of its right operand.

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.

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
    this
    super
    null
    true
    false
    $
        __FILE__
    __LINE__
    IntegerLiteral
    FloatLiteral
    CharacterLiteral
    StringLiterals
    ArrayLiteral
    AssocArrayLiteral
    FunctionLiteral
    AssertExpression
    MixinExpression
    ImportExpression
    BasicType . Identifier
    Typeof
    TypeidExpression
    IsExpression
    ( Expression )
        TraitsExpression

.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'
}

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.

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:

immutable(char)*
immutable(wchar)*
immutable(dchar)*
immutable(char)[]
immutable(wchar)[]
immutable(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, 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.

Function Literals

FunctionLiteral:
    function Typeopt ParameterAttributes opt FunctionBody
    delegate Typeopt ParameterAttributes opt FunctionBody
    ParameterAttributes FunctionBody
    FunctionBody

ParameterAttributes:
    Parameters
       Parameters FunctionAttributes
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 expression. 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 Expression, if present, must be implicitly convertible to type const(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 )
    typeid ( Expression )

If Type, returns an instance of class TypeInfo corresponding to Type.

If Expression, returns an instance of class TypeInfo corresponding to the type of the Expression. If the type is a class, it returns the TypeInfo of the dynamic type (i.e. the most derived type). The Expression is always executed.

class A { }
class B : A { }

void main()
{
    writeln(typeid(int));  // int
    uint i;
    writeln(typeid(i++));  // uint
    writeln(i);            // 1
    A a = new B();
    writeln(typeid(a));    // B
    writeln(typeid(typeof(a)));  // A
}

IsExpression

IsExpression:
    is ( Type )
    is ( Type : TypeSpecialization )
    is ( Type == TypeSpecialization )
    is ( Type Identifier )
    is ( Type Identifier : TypeSpecialization )
    is ( Type Identifier == TypeSpecialization )
    is ( Type Identifier : TypeSpecialization , TemplateParameterList )
    is ( Type Identifier == TypeSpecialization , TemplateParameterList )

TypeSpecialization:
    Type
    struct
    union
    class
    interface
    enum
    function
    delegate
    super
        const
    immutable
    inout
    shared
    return
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 struct union class interface enum function delegate const immutable shared then the condition is satisifed if Type is one of those.

    alias short bar;

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");
}
  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 struct union class interface enum function delegate const immutable shared 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
    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
    delegate | the function type of the delegate
    return | the return type of the function, delegate, or function pointer
    const | Type
    immutable | Type
    shared | Type
    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
}
  7. is ( Type Identifier : TypeSpecialization , TemplateParameterList )
    is ( Type Identifier == TypeSpecialization , TemplateParameterList )

    More complex types can be pattern matched; the TemplateParameterList declares symbols based on the parts of the pattern that are matched, analogously to the way implied template parameters are matched.

    import std.stdio;

void main()
{
  alias long[char[]] AA;

  static if (is(AA T : T[U], U : const char[]))
  {
    writefln(typeid(T));	// long
    writefln(typeid(U));	// const char[]
  }

  static if (is(AA A : A[B], B : int))
  {
    assert(0);  // should not match, as B is not an int
  }

  static if (is(int[10] W : W[V], int V))
  {
    writefln(typeid(W));	// int
    writefln(V);		// 10
  }

  static if (is(int[10] X : X[Y], int Y : 5))
  {
    assert(0);	// should not match, Y should be 10
  }
}

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.

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


Statements

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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
    CaseRangeStatement
    DefaultStatement

NonEmptyStatementNoCaseNoDefault:
    LabeledStatement
    ExpressionStatement
    DeclarationStatement
    IfStatement
    WhileStatement
    DoStatement
    ForStatement
    ForeachStatement
    SwitchStatement
    FinalSwitchStatement
    ContinueStatement
    BreakStatement
    ReturnStatement
    GotoStatement
    WithStatement
    SynchronizedStatement
    TryStatement
    ScopeGuardStatement
    ThrowStatement
    AsmStatement
    PragmaStatement
    MixinStatement
    ForeachRangeStatement
    ConditionalStatement
    StaticAssert
    TemplateMixin

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:
    ref BasicType Declarator
    BasicType Declarator
    ref Identifier
    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";

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 Ranges

Iteration over struct and class objects can be done with ranges, which means the following properties must be defined:

Foreach Range Properties
Property | Purpose
.empty | returns true if no more elements
.popFront | move the left edge of the range right one
.popBack | move the right edge of the range left one
.front | return the leftmost element of the range
.back | return the rightmost element of the range

Meaning:

foreach (e; range) { ... }

translates to:

for (auto __r = range; !__r.empty; __r.next)
{   auto e = __r.head;
   ...
}

Similarly:

foreach_reverse (e; range) { ... }

translates to:

for (auto __r = range; !__r.empty; __r.retreat)
{   auto e = __r.toe;
   ...
}

If the foreach range properties do not exist, the opApply method will be used instead.

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 array[2];

    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

CaseRangeStatement:
    case FirstExp : .. case LastExp : ScopeStatementList

FirstExp:
    AssignExpression

LastExp:
    AssignExpression

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.

A CaseRangeStatement is a shorthand for listing a series of case statements from FirstExp to LastExp.

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 reason for this is to catch the common programming error of adding a new value to an enum, but failing to account for the extra value in switch statements. This behavior is unlike C or C++.

The case expressions must all evaluate to a constant value or array, or a runtime initialized const or immutable variable of integral type. They must be implicitly convertible to the type of the switch Expression.

Case expressions must all evaluate to distinct values. Const or immutable variables must all have different names. If they share a value, the first case statement with that value gets control. 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.

Final Switch Statement

FinalSwitchStatement:
    final switch ( Expression ) ScopeStatement

A final switch statement is just like a switch statement, except that:

  • No DefaultStatement is allowed.
  • No CaseRangeStatements are allowed.
  • If the switch Expression is of enum type, all the enum members must appear in the CaseStatements.
  • The case expressions cannot evaluate to a run time initialized value.

Continue Statement

ContinueStatement:
    continue;
    continue Identifier ;
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;
    break Identifier ;
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;
    return Expression ;
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.

Expression is allowed even if the function specifies a void return type. The Expression will be evaluated, but nothing will be returned. If the Expression has no side effects, and the return type is void, then it is illegal.

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;
}

Use of with object symbols that shadow local symbols with the same identifier are not allowed. This is to reduce the risk of inadvertant breakage of with statements when new members are added to the object declaration.

struct S
{
    float x;
}

void main()
{
    int x;
    S s;
    with (s)
    {
        x++;  // error, shadows the int x declaration
    }
}

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.

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
}

Foreach Range Statement

A foreach range statement loops over the specified range.
ForeachRangeStatement:
    Foreach (ForeachType ; LwrExpression .. UprExpression ) ScopeStatement

LwrExpression:
    Expression

UprExpression:
    Expression

ForeachType declares a variable with either an explicit type, or a type inferred from LwrExpression and UprExpression. The ScopeStatement is then executed n times, where n is the result of UprExpression - LwrExpression. If UprExpression is less than or equal to LwrExpression, the ScopeStatement is executed zero times. If Foreach is foreach, then the variable is set to LwrExpression, then incremented at the end of each iteration. If Foreach is foreach_reverse, then the variable is set to UprExpression, then decremented before each iteration. LwrExpression and UprExpression are each evaluated exactly once, regardless of how many times the ScopeStatement is executed.

import std.stdio;

int foo()
{
    writefln("foo");
    return 10;
}

void main()
{
    foreach (i; 0 .. foo())
    {
    writef(i);
    }
}

Prints:

foo0123456789

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


Arrays

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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. Unlike in C and D version 1, static arrays are passed to functions by value. Static arrays can also be returned by 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 symbol $ represents the length of the array.

int[4] foo;
int[]  bar = foo;
int*   p = &foo[0];

// These expressions are equivalent:
bar[]
bar[0 .. 4]
bar[0 .. $]
bar[0 .. bar.length]

p[0 .. $]		// '$' is not defined, since p is not an array
bar[0]+$		// '$' is not defined, out of scope of [ ]

bar[$-1]	// retrieves last element of the array

Array Properties

Static array properties are:

Static Array Properties
Property | Description
.init | Returns an array literal with each element of the literal being the .init property of the array 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 on 32 bit machines.
.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 resizing in place would overwrite valid data in the array.

For example:
char[] a = new char[20];
char[] b = a[0..10];
char[] c = a[10..20];
char[] d = a;

b.length = 15;    // always reallocates because extending in place would
                  // overwrite other data in a.
b[11] = 'x';      // a[11] and c[1] are not affected

d.length = 1;
d.length = 20;    // also reallocates, because doing this will overwrite a and
                  // c

c.length = 12;    // may reallocate in place if space allows, because nothing
                  // was allocated after c.
c[5] = 'y';       // may affect contents of a, but not b or d because those
                  // were reallocated.

a.length = 25;    // This always reallocates because if c extended in place,
                  // then extending a would overwrite c.  If c didn't
                  // reallocate in place, it means there was not enough space,
                  // which will still be true for a.
a[15] = 'z';      // does not affect c, because either a or c has reallocated.

To guarantee copying behavior, use the .dup property to ensure a unique array that can be resized. Also, one may use the phobos .capacity property to determine how many elements can be appended to the array without reallocating.

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; 1; 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.

Also, you may wish to utilize the phobos reserve function to pre-allocate array data to use with the append operator.

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, a RangeError 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 (ArrayBoundsError)
{
    // 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 Static 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 static when they appear in global scope. Otherwise, they need to be marked with const or static storage classes to make them static 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[] str1 = "abc";                // error, "abc" is not mutable
char[] str2 = "abc".dup;            // ok, make mutable copy
immutable(char)[] str3 = "abc";     // ok
immutable(char)[] str4 = str1;      // error, str4 is not mutable
immutable(char)[] str5 = str1.idup; // ok, make immutable copy

The name string is aliased to immutable(char)[], so the above declarations could be equivalently written as:

char[] str1 = "abc";       // error, "abc" is not mutable
char[] str2 = "abc".dup;   // ok, make mutable copy
string str3 = "abc";       // ok
string str4 = str1;        // error, str4 is not mutable
string str5 = str1.idup;   // ok, make immutable copy

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(immutable(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 char[], wchar[], and dchar[] 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 char*, and a string literal can be implicitly cast to a 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 way D arrays are laid out, the length comes first, so the following works:

printf("the string is '%.*s'\n", str);

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

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[char[]] b;		// associative array b of ints that are
            // indexed by an array of characters.
            // The KeyType is char[]
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 != null)
    ...

KeyTypes 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()
  • bool 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; }

    bool 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:

const hash_t toHash();
const bool opEquals(ref const KeyType s);
const int opCmp(ref const KeyType s);

For example:

import std.string;

struct MyString
{
    string str;

    const hash_t toHash()
    {   hash_t hash;
    foreach (char c; str)
        hash = (hash * 9) + c;
    return hash;
    }

    const bool opEquals(ref const MyString s)
    {
    return std.string.cmp(this.str, s.str) == 0;
    }

    const int opCmp(ref const 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 typically 8.
.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.
.byKey() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the keys of the associative array.
.byValue() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the values of the associative array.
.get(Key key, lazy Value defaultValue) | Looks up key; if it exists returns corresponding value else evaluates and returns defaultValue.

Associative Array Example: word count

import std.file;         // D file I/O
import std.stdio;

int main (string[] args)
{
    int word_total;
    int line_total;
    int char_total;
    int[char[]] dictionary;

    writefln("   lines   words   bytes file");
    for (int i = 1; i < args.length; ++i)      // program arguments
    {
    char[] input;            // input buffer
    int w_cnt, l_cnt, c_cnt; // word, line, char counts
    int inword;
    int wstart;

    // read file into input[]
    input = cast(char[])std.file.read(args[i]);

    foreach (j, char 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 = 1;
            ++w_cnt;
        }
        }
        else if (inword)
        {
        char[] word = input[wstart .. j];
        dictionary[word]++;        // increment count for word
        inword = 0;
        }
        ++c_cnt;
    }
    if (inword)
    {
        char[] word = input[wstart .. input.length];
        dictionary[word]++;
    }
    writefln("%8d%8d%8d %s", l_cnt, w_cnt, c_cnt, args[i]);
    line_total += l_cnt;
    word_total += w_cnt;
    char_total += c_cnt;
    }

    if (args.length > 2)
    {
    writef("-------------------------------------\n%8d%8d%8d total",
        line_total, word_total, char_total);
    }

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

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


Associative Arrays

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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[char[]] b;		// associative array b of ints that are
            // indexed by an array of characters.
            // The KeyType is char[]
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 != 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()
  • bool 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; }

    bool opEquals(Object o)
    {	Foo f = cast(Foo) o;
    return f && a == foo.a && b == foo.b;
    }

    int opCmp(Object o)
    {	Foo f = cast(Foo) o;
    if (!f)
        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:

const hash_t toHash();
const bool opEquals(ref const KeyType s);
const int opCmp(ref const KeyType s);

For example:

import std.string;

struct MyString
{
    string str;

    const hash_t toHash()
    {   hash_t hash;
    foreach (char c; s)
        hash = (hash * 9) + c;
    return hash;
    }

    const bool opEquals(ref const MyString s)
    {
    return std.string.cmp(this.str, s.str) == 0;
    }

    const int opCmp(ref const 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 typically 8.
.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.
.byKey() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the keys of the associative array.
.byValue() | Returns a delegate suitable for use as an Aggregate to a ForeachStatement which will iterate over the values of the associative array.
.get(Key key, lazy Value defaultValue) | Looks up key; if it exists returns corresponding value else evaluates and returns defaultValue.

Associative Array Example: word count

import std.file;         // D file I/O
import std.stdio;

int main (string[] args)
{
    int word_total;
    int line_total;
    int char_total;
    int[char[]] dictionary;

    writefln("   lines   words   bytes file");
    for (int i = 1; i < args.length; ++i)      // program arguments
    {
    char[] input;            // input buffer
    int w_cnt, l_cnt, c_cnt; // word, line, char counts
    int inword;
    int wstart;

    // read file into input[]
    input = cast(char[])std.file.read(args[i]);

    foreach (j, char 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 = 1;
            ++w_cnt;
        }
        }
        else if (inword)
        {
        char[] word = input[wstart .. j];
        dictionary[word]++;        // increment count for word
        inword = 0;
        }
        ++c_cnt;
    }
    if (inword)
    {
        char[] word = input[wstart .. input.length];
        dictionary[word]++;
    }
    writefln("%8d%8d%8d %s", l_cnt, w_cnt, c_cnt, args[i]);
    line_total += l_cnt;
    word_total += w_cnt;
    char_total += c_cnt;
    }

    if (args.length > 2)
    {
    writef("-------------------------------------\n%8d%8d%8d total",
        line_total, word_total, char_total);
    }

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

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


Structs, Unions

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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 | 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 | X
postblit/copy constructors | X |  |  | X | X
destructors | X | X |  | X | X
shared static constructors | X | X |  |  |
shared static destructors | X | X |  |  |
RAII | X | X |  | X | X
assign overload | X |  |  | 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 |  |  |
const/immutable/shared | X | X |  |  |
inner nesting | YES | YES |  |  |
AggregateDeclaration:
    struct Identifier StructBody
    union Identifier StructBody
    struct Identifier ;
    union Identifier ;
    StructTemplateDeclaration
    UnionTemplateDeclaration

StructBody:
    { }
    { StructBodyDeclarations }

StructBodyDeclarations:
    StructBodyDeclaration
    StructBodyDeclaration StructBodyDeclarations

StructBodyDeclaration:
    DeclDef
    StructAllocator
    StructDeallocator
        StructPostblit
    AliasThis

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.

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 X { int a; int b; int c; int d = 7;}
static X x = { a:1, b:2};	      // c is set to 0, d to 7
static X 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 X 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 X 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 s = { 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

Const and Invariant Structs

A struct declaration can have a storage class of const, immutable or shared. It has an equivalent effect as declaring each member of the struct as const, immutable or shared.

const struct S { int a; int b = 2; }

void main()
{
    S s = S(3);    // initializes s.a to 3
    S t;           // initializes t.a to 0
    t = s;         // ok, t.a is now 3
    t.a = 4;       // error, t.a is const
}

Struct Constructors

Struct constructors are used to initialize an instance of a struct. The ParameterList may not be empty. Struct instances that are not instantiated with a constructor are default initialized to their .init value.

Struct Postblits

StructPostblit:
    this(this) FunctionBody

Copy construction is defined as initializing a struct instance from another struct of the same type. Copy construction is divided into two parts:

  1. blitting the fields, i.e. copying the bits
  2. running postblit on the result

The first part is done automatically by the language, the second part is done if a postblit function is defined for the struct. The postblit has access only to the destination struct object, not the source. Its job is to ‘fix up’ the destination as necessary, such as making copies of referenced data, incrementing reference counts, etc. For example:

struct S
{
   int[] a;    // array is privately owned by this instance
   this(this)
   {
       a = a.dup;
   }
   ~this()
   {
       delete a;
   }
}

Struct Destructors

Destructors are called when an object goes out of scope. Their purpose is to free up resources owned by the struct object.

Assignment Overload

While copy construction takes care of initializing an object from another object of the same type, assignment is defined as copying the contents of one object over another, already initialized, type:

struct S { ... }
S s;      // default construction of s
S t = s;  // t is copy-constructed from s
t = s;    // t is assigned from s

Struct assignment t=s is defined to be semantically equivalent to:

t = S.opAssign(s);

where opAssign is a member function of S:

S* opAssign(S s)
{   ... bitcopy *this into tmp ...
    ... bitcopy s into *this ...
    ... call destructor on tmp ...
    return this;
}

While the compiler will generate a default opAssign as needed, a user-defined one can be supplied. The user-defined one must still implement the equivalent semantics, but can be more efficient.

One reason a custom opAssign might be more efficient is if the struct has a reference to a local buffer:

struct S
{
    int[] buf;
    int a;

    S* opAssign(ref const S s)
    {
    a = s.a;
    return this;
    }

    this(this)
    {
    buf = buf.dup;
    }

    ~this()
    {
    delete buf;
    }
}

Here, S has a temporary workspace buf[]. The normal postblit will pointlessly free and reallocate it. The custom opAssign will reuse the existing storage.

Nested Structs

A nested struct is a struct that is declared inside the scope of a function or a templated struct that has aliases to local functions as a template argument. Nested structs have member functions. It has access to the context of its enclosing scope (via an added hidden field).

void foo()
{   int i = 7;
    struct SS
    {
        int x,y;
        int bar() { return x + i + 1; }
    }
    SS s;
    s.x = 3;
    s.bar(); // returns 11
}

Nested structs cannot be used as fields or as the element type of an array:

void foo()
{   int i = 7;
    struct SS
    {
        int x,y;
        int bar() { return x + i + 1; }
    }
    struct DD
    {
        SS s;    // error, cannot be field
    }
    SS[3] a;     // error, cannot be array element
    SS[] a;      // error, cannot be array element
}

A struct can be prevented from being nested by using the static attribute, but then of course it will not be able to access variables from its enclosing scope.

void foo()
{   int i = 7;
    static struct SS
    {
        int x,y;
        int bar()
        {
           return i;   // error, SS is not a nested struct
        }
    }
}

A templated struct can become a nested struct if it has a local function passed as an aliased argument:

struct A(alias F)
{
    int fun(int i) { return F(i); }
}

A!(F) makeA(alias F)() {return A!(F)(); }

void main()
{
    int x = 40;
    int fun(int i) { return x + i; }
    A!(fun) a = makeA!(fun)();
    a.fun(2);
}

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


Classes

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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 BaseClassList ClassBody
    ClassTemplateDeclaration

BaseClassList:
    Empty
    : SuperClass
    : SuperClass , InterfaceClasses
    : InterfaceClass

SuperClass:
    Identifier
    Protection Identifier

InterfaceClasses:
    InterfaceClass
    InterfaceClass , InterfaceClasses

InterfaceClass:
    Identifier
    Protection Identifier

Protection:
    private
    package
    public
    export

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
    • Shared Static Constructors
    • Shared Static Destructors
    • Class Invariants
    • Unit Tests
    • Class Allocators
    • Class Deallocators
    • Alias This
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;

Fields

Class members are always accessed with the . operator. There are no :: or -> operators as in C++.

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
        TemplatedConstructor

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:
    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 OutOfMemoryException 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 defined as 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
    }
}
static this() is called by the startup code before main() is called. If it 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
}

Shared Static Constructors

SharedStaticConstructor:
    shared static this() FunctionBody

Shared static constructors are executed before any StaticConstructors, and are intended for initializing any shared global data.

Shared Static Destructors

SharedStaticDestructor:
    shared static ~this() FunctionBody

Shared static destructors are executed at program termination in the reverse order that SharedStaticConstructors were executed.

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, before a public or exported member is run, and after a public or exported function finishes.

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.

Alias This

AliasThis:
    alias Identifier this;

An AliasThis declaration names another class or struct member to which any undefined lookups will be forwarded. The Identifier names that member.

A class or struct can be implicitly converted to the AliasThis member.

There is only one AliasThis allowed per class or struct.

struct S
{   int x;
    alias x this;
}

int foo(int i) { return i * 2; }

void test()
{
    S s;
    s.x = 7;
    int i = -s;   // i == -7
    i = s + 8;    // i == 15
    i = s + s;    // i == 14
    i = 9 + s;    // i == 16
    i = foo(s);   // implicit conversion to int
}

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 ParenArgumentListopt class ParenArgumentListopt SuperClassopt InterfaceClassesopt ClassBody

ParenArgumentList:
    ( ArgumentList )

which is equivalent to:

class Identifier : SuperClass InterfaceClasses
    ClassBody

new (ArgumentList) Identifier (ArgumentList);

where Identifier is the name generated for the anonymous nested class.

Const

Immutable and Shared Classes,

If a ClassDeclaration has a const, immutable or shared storage class, then it is as if each member of the class was declared with that storage class. If a base class is const, immutable or shared, then all classes derived from it are also const, immutable or shared.

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


Interfaces

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

Interfaces

InterfaceDeclaration:
    interface Identifier BaseInterfaceList InterfaceBody
    InterfaceTemplateDeclaration

BaseInterfaceList:
    Empty
    : InterfaceClasses

InterfaceBody:
    { }
    { InterfaceBodyDeclarations }

InterfaceBodyDeclarations:
    InterfaceBodyDeclaration
    InterfaceBodyDeclaration InterfaceBodyDeclarations

InterfaceBodyDeclaration:
    { DeclDef }

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.

C++ Interfaces are another form of interfaces, meant to be binary compatible with C++.

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

Virtual interface member functions do not have implementations. Interfaces are expected to implement static or final functions.

interface D
{
    void bar() { }	// error, implementation not allowed
    static void foo() { } // ok
    final void abc() { } // ok
}

Classes that inherit from an interface may not override final or static interface member functions.

interface D {
    void bar();
    static void foo() { }
    final void abc() { }
}

class C : D {
    void bar() { } // ok
    void foo() { } // error, cannot override static D.foo()
    void abc() { } // error, cannot override final D.abc()
}

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

Interfaces with Contracts

Interface member functions can have contracts even though there is no body for the function. The contracts are inherited by any class member function that implements that interface member function.

interface I
{
    int foo(int i)
      in { assert(i > 7); }
      out (result) { assert(result & 1); }

    void bar();
}

Const and Immutable Interfaces

If an interface has const or immutable storage class, then all members of the interface are const or immutable. This storage class is not inherited.

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.

C++ Interfaces

C++ interfaces are interfaces declared with C++ linkage:

extern (C++) interface Ifoo
{
    void foo();
    void bar();
}

which is meant to correspond with the following C++ declaration:

class Ifoo
{
    virtual void foo();
    virtual void bar();
};

Any interface that derives from a C++ interface is also a C++ interface. A C++ interface differs from a D interface in that:

  • 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.
  • The C++ calling convention is the default convention for its member functions, rather than the D calling convention.
  • The first member of the vtbl[] is not the pointer to the Interface, but the first virtual function pointer.

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


Enums

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

Enums - Enumerated Types

EnumDeclaration:
    enum EnumTag EnumBody
    enum EnumBody
    enum EnumTag : EnumBaseType EnumBody
    enum : EnumBaseType EnumBody

EnumTag:
    Identifier

EnumBaseType:
    Type

EnumBody:
    ;
    { EnumMembers }

EnumMembers:
    EnumMember
    EnumMember ,
    EnumMember , EnumMembers

EnumMember:
    Identifier
    Identifier = AssignExpression
        Type = 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, and the first EnumMember has an initializer, it is set to the type of that initializer. Otherwise, it defaults to type int.

Named enum members may not have individual Types.

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.

Enums must have at least one member.

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

The EnumBaseType of named enums must support comparison in order to compute the .max and .min properties.

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.

If omitted, the EnumMembers can have different types. Those types are given by the first of:

  1. The Type, if present.
  2. The type of the AssignExpression, if present.
  3. The type of the previous EnumMember, if present.
  4. 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.

enum : string
{
    A = "hello",
    B = "betty",
    C     // error, cannot add 1 to "betty"
}

enum
{
    A = 1.2f,   // A is 1.2f of type float
    B,          // B is 2.2f of type float
    int C = 3,  // C is 3 of type int
    D           // D is 4 of type int
}

Manifest Constants

If there is only one member of an anonymous enum, the { } can be omitted:

enum i = 4;      // i is 4 of type int
enum long l = 3; // l is 3 of type long

Such declarations are not lvalues, meaning their address cannot be taken.

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


Functions

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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.

Pure Functions

Pure functions are functions that produce the same result for the same arguments. To that end, a pure function:

  • does not read or write any global mutable state
  • cannot call functions that are not pure
  • can override an impure function, but an impure function cannot override a pure one
  • is covariant with an impure function
  • cannot perform I/O

As a concession to practicality, a pure function can:

  • allocate memory via a NewExpression
  • terminate the program
  • read and write the floating point exception flags
  • read and write the floating point mode flags, as long as those flags are restored to their initial state upon function entry

A pure function can throw exceptions.

int x;
immutable int y;
const int* pz;

pure int foo(int i,
             char* p,
             const char* q,
             immutable int* s)
{
    x = i;    // error, modifying global state
    i = x;    // error, reading mutable global state
    i = y;    // ok, reading immutable global state
    i = *pz;  // error, reading const global state
    return i;
}

Nothrow Functions

Nothrow functions do not throw any exceptions derived from class Exception.

Nothrow functions are covariant with throwing ones.

Ref Functions

Ref functions allow functions to return by reference. This is analogous to ref function parameters.

ref int foo()
{   auto p = new int;
    return *p;
}
...
foo() = 3;  // reference returns can be lvalues

Auto Functions

Auto functions have their return type inferred from any ReturnStatements in the function body.

An auto function is declared without a return type. If it does not already have a storage class, use the auto storage class.

If there are multiple ReturnStatements, the types of them must match exactly. If there are no ReturnStatements, the return type is inferred to be void.

auto foo(int i)
{
    return i + 3;  // return type is inferred to be int
}

Auto Ref Functions

Auto ref functions infer their return type just as auto functions do. In addition, they become ref functions if the return expression is an lvalue, and it would not be a reference to a local or a parameter.

auto ref foo(int x)     { return x; }  // value return
auto ref foo()          { return 3; }  // value return
auto ref foo(ref int x) { return x; }  // ref return
auto ref foo(out int x) { return x; }  // ref return
auto ref foo() { static int x; return x; }  // ref return

The lexically first ReturnStatement determines the ref-ness of a function:

auto ref foo(ref int x) { return 3; return x; }  // ok, value return
auto ref foo(ref int x) { return x; return 3; }  // error, ref return, 3 is not an lvalue

Inout Functions

Functions that deal with mutable, const, or immutable types with equanimity often need to transmit their type to the return value:

int[] foo(int[] a, int x, int y) { return a[x .. y]; }
const(int)[] foo(const(int)[] a, int x, int y) { return a[x .. y]; }
immutable(int)[] foo(immutable(int)[] a, int x, int y) { return a[x .. y]; }

The code generated by these three functions is identical. To indicate that these can be one function, the inout type constructor is employed:

inout(int)[] foo(inout(int)[] a, int x, int y) { return a[x .. y]; }

The inout forms a wildcard that stands in for any of mutable, const or immutable. When the function is called, the inout of the return type is changed to whatever the mutable, const, or immutable status of the argument type to the parameter inout was.

Inout types can be implicitly converted to const, but to nothing else. Other types cannot be implicitly converted to inout. Casting to or from inout is not allowed in @safe functions.

If an inout appears in a function parameter list, it must also appear in the return type.

A set of arguments to a function with inout parameters is considered a match if any inout argument types match exactly, or:

  1. No argument types are composed of inout types.
  2. A mutable, const or immutable argument type can be matched against each corresponding parameter inout type.

If such a match occurs, if every match is mutable, then the inout is considered matched with mutable. If every match is immutable, then the inout is considered matched with immutable. Otherwise, the inout is considered matched with const. The inout in the return type is then rewritten to be the inout matched attribute.

Global and static variable types cannot have any inout components.

Note: Shared types are not overlooked. Shared types cannot be matched with inout.

Property Functions

Property functions are tagged with the @property attribute. They can be called without parentheses (hence acting like properties).

struct S
{
    int m_x;
    @property
    {   int x() { return m_x; }
        int x(int newx) { return m_x = newx; }
    }
}

void foo()
{
    S s;
    s.x = 3;   // calls s.x(int)
    bar(s.x);  // calls bar(s.x())
}

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);	// issues runtime error (instead of calling 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)
}

If such an AliasDeclaration is not used, the derived class's functions completely override all the functions of the same name in the base class, even if the types of the parameters in the base class functions are different. If, through implicit conversions to the base class, those other functions do get called, an std.HiddenFuncError exception is raised:

import std.hiddenfunc;

class A
{
     void set(long i) { }
     void set(int i)  { }
}
class B : A
{
     void set(long i) { }
}

void foo(A a)
{   int i;
    try
    {
        a.set(3);   // error, throws runtime exception since
                    // A.set(int) should not be available from B
    }
    catch (HiddenFuncError o)
    {
    i = 1;
    }
    assert(i == 1);
}

void main()
{
    foo(new B);
}

If an HiddenFuncError exception is thrown in your program, the use of overloads and overrides needs to be reexamined in the relevant classes.

The HiddenFuncError exception is not thrown if the hidden function is disjoint, as far as overloading is concerned, from all the other virtual functions is the inheritance hierarchy.

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. match with conversion to const
  4. 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.

Literals do not match ref or out parameters.

If two or more functions have the same match level, then partial ordering is used to try to find the best match. Partial ordering finds the most specialized function. If neither function is more specialized than the other, then it is an ambiguity error. Partial ordering is determined for functions f() and g() by taking the parameter types of f(), constructing a list of arguments by taking the default values of those types, and attempting to match them against g(). If it succeeds, then g() is at least as specialized as f(). For example:

class A { }
class B : A { }
class C : B { }
void foo(A);
void foo(B);

void test()
{
  C c;
  /* Both foo(A) and foo(B) match with implicit conversion rules.
   * Applying partial ordering rules,
   * foo(B) cannot be called with an A, and foo(A) can be called
   * with a B. Therefore, foo(B) is more specialized, and is selected.
   */
  foo(c); // calls foo(B)
}

A function with a variadic argument is considered less specialized than a function without.

Functions defined with non-D linkage cannot be overloaded. because the name mangling does not take the parameter types into account.

Overload Sets

Functions declared at the same scope overload against each other, and are called an Overload Set. A typical example of an overload set are functions defined at module level:

module A;
void foo() { }
void foo(long i) { }

A.foo() and A.foo(long) form an overload set. A different module can also define functions with the same name:

module B;
class C { }
void foo(C) { }
void foo(int i) { }

and A and B can be imported by a third module, C. Both overload sets, the A.foo overload set and the B.foo overload set, are found. An instance of foo is selected based on it matching in exactly one overload set:

import A;
import B;

void bar(C c)
{
    foo();    // calls A.foo()
    foo(1L);  // calls A.foo(long)
    foo(c);   // calls B.foo(C)
    foo(1,2); // error, does not match any foo
    foo(1);   // error, matches A.foo(long) and B.foo(int)
    A.foo(1); // calls A.foo(long)
}

Even though B.foo(int) is a better match than A.foo(long) for foo(1), it is an error because the two matches are in different overload sets.

Overload sets can be merged with an alias declaration:

import A;
import B;

alias A.foo foo;
alias B.foo foo;

void bar(C c)
{
    foo();    // calls A.foo()
    foo(1L);  // calls A.foo(long)
    foo(c);   // calls B.foo(C)
    foo(1,2); // error, does not match any foo
    foo(1);   // calls B.foo(int)
    A.foo(1); // calls A.foo(long)
}

Function Parameters

Parameter storage classes are in, out, ref, lazy, final, const, immutable, or scope. For example:
int foo(in int x, out int y, ref int z, int q);

x is in, y is out, z is ref, and q is none.

The in storage class is equivalent to const scope.

If no storage class is specified, the parameter becomes a mutable copy of its argument.

  • 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.

out parameters are set to the default initializer for the type of it. For example:

void foo(out int x)
{
    // x is set to 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(ref 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. The implementiations of these variadic functions have a special local variable declared for them, _argptr, which is a void* pointer to the first of the variadic arguments. To access the arguments, _argptr must be cast to a pointer to the expected argument type:
foo(3, 4, 5);	// first variadic argument is 5

int foo(int x, int y, ...)
{   int z;

    z = *cast(int*)_argptr;	// z is set to 5
}
To protect against the vagaries of stack layouts on different CPU architectures, use std.c.stdarg to access the variadic arguments:
import std.c.stdarg;

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
These variadic functions have a special local variable declared for them, _argptr, which is a void* pointer to the first of the variadic arguments. To access the arguments, _argptr must be cast to a pointer to the expected argument type:
foo(3, 4, 5);	// first variadic argument is 5

int foo(int x, int y, ...)
{   int z;

    z = *cast(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;

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 = *cast(int *)_argptr;
        _argptr += int.sizeof;
        writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(long))
    {
        long j = *cast(long *)_argptr;
        _argptr += long.sizeof;
        writefln("\t%d", j);
    }
    else if (_arguments[i] == typeid(double))
    {
        double d = *cast(double *)_argptr;
        _argptr += double.sizeof;
        writefln("\t%g", d);
    }
    else if (_arguments[i] == typeid(Foo))
    {
        Foo f = *cast(Foo*)_argptr;
        _argptr += Foo.sizeof;
        writefln("\t%X", f);
    }
    else if (_arguments[i] == typeid(Bar))
    {
        Bar b = *cast(Bar*)_argptr;
        _argptr += Bar.sizeof;
        writefln("\t%X", b);
    }
    else
        assert(0);
    }
}

void main()
{
    Foo f = new Foo();
    Bar b = new Bar();

    writefln("%X", 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
To protect against the vagaries of stack layouts on different CPU architectures, use std.stdarg to access the variadic arguments:
import std.stdio;
import std.stdarg;

void foo(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%X", f);
    }
    else
        assert(0);
    }
}

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;
    char[] s;

    this(int x, char[] 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.

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
}

The solution is to use a delegate:

void test()
{
    void delegate() fp;
    void foo() { fp(); }
    void bar() { foo(); }
    fp = &bar;
}

Future directions: This restriction may be removed.

Delegates, Function Pointers, and 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 referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error.

int* bar()
{   int b;
    test();
    int i = dg();	// ok, test.a is in a closure and still 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 Function Literals.

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(char[][] args) { ... }
int main() { ... }
int main(char[][] args) { ... }

Compile Time Function Execution (CTFE)

A subset of functions can be executed at compile time. This is useful when constant folding algorithms need to include recursion and looping. In order to be executed at compile time, a function must meet the following criteria:

  1. function arguments must all be:
    • integer literals
    • floating point literals
    • character literals
    • string literals
    • array literals where the members are all items in this list
    • associative array literals where the members are all items in this list
    • struct literals where the members are all items in this list
    • const variables initialized with a member of this list
    • delegates
    • pointers to functions
    • delegate literals
    • function literals
  2. function parameters may not be C-style variadic
  3. the function may not be synchronized
  4. expressions in the function may not:
    • throw exceptions
    • use pointers or classes
    • reference any global state or variables
    • reference any local static variables
    • delete
    • call any function that is not executable at compile time
  5. the following statement types are not allowed:
    • synchronized statements
    • throw statements
    • with statements
    • scope statements
    • try-catch-finally statements
    • labeled break and continue statements
  6. as a special case, the following properties can be executed at compile time:
    .dup
    .length
    .keys
    .values

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.

Function Safety

Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior. Undefined behavior is often used as a vector for malicious attacks.

Safe Functions

Safe functions are marked with the @safe attribute.

The following operations are not allowed in safe functions:

  • No casting from a pointer type to any type other than void*.
  • No casting from any non-pointer type to a pointer type.
  • No modification of pointer values.
  • Cannot access unions that have pointers or references overlapping with other types.
  • Calling any system functions.
  • No catching of exceptions that are not derived from class Exception.
  • No inline assembler.
  • No explicit casting of mutable objects to immutable.
  • No explicit casting of immutable objects to mutable.
  • No explicit casting of thread local objects to shared.
  • No explicit casting of shared objects to thread local.
  • No taking the address of a local variable or function parameter.
  • Cannot access __gshared variables.

Functions nested inside safe functions default to being safe functions.

Safe functions are covariant with trusted or system functions.

Note: The verifiable safety of functions may be compromised by bugs in the compiler and specification. Please report all such errors so they can be corrected.

Trusted Functions

Trusted functions are marked with the @trusted attribute.

Trusted functions are guaranteed by the programmer to not exhibit any undefined behavior if called by a safe function. Generally, trusted functions should be kept small so that they are easier to manually verify.

Trusted functions may call safe, trusted, or system functions.

Trusted functions are covariant with safe or system functions.

System Functions

System functions are functions not marked with @safe or @trusted and are not nested inside @safe functions. System functions may be marked with the @system attribute. A function being system does not mean it actually is unsafe, it just means that the compiler is unable to verify that it cannot exhibit undefined behavior.

System functions are not covariant with trusted or safe functions.

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


Operator Overloading

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

Operator Overloading

Operator overloading is accomplished by rewriting operators whose operands are class or struct objects into calls to specially named member functions. No additional syntax is used.

  • Unary Operator Overloading
  • Cast Operator Overloading
  • Binary Operator Overloading
  • Overloading == and !=
  • Overloading < <=, > and >=
  • Function Call Operator Overloading
  • Assignment Operator Overloading
  • Op Assignment Operator Overloading
  • Index Operator Overloading
  • Slice Operator Overloading
  • Forwarding

Unary Operator Overloading

Overloadable Unary Operators
op | rewrite
-e | e.opUnary!("-")()
+e | e.opUnary!("+")()
~e | e.opUnary!("~")()
*e | e.opUnary!("*")()
++e | e.opUnary!("++")()
--e | e.opUnary!("--")()

For example, in order to overload the - (negation) operator for struct S, and no other operator:

struct S {
    int m;

    int opUnary(string s)() if (s == "-") {
        return -m;
    }
}

int foo(S s) {
    return -s;
}

Postincrement e++ and Postdecrement e-- Operators

These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators:

Postfix Operator Rewrites
op | rewrite
e-- | (auto t = e, --e, t)
e++ | (auto t = e, ++e, t)

Overloading Index Unary Operators

Overloadable Index Unary Operators
op | rewrite
-a[b1, b2, ... bn] | a.opIndexUnary!("-")(b1, b2, ... bn)
+a[b1, b2, ... bn] | a.opIndexUnary!("+")(b1, b2, ... bn)
~a[b1, b2, ... bn] | a.opIndexUnary!("~")(b1, b2, ... bn)
*a[b1, b2, ... bn] | a.opIndexUnary!("*")(b1, b2, ... bn)
++a[b1, b2, ... bn] | a.opIndexUnary!("++")(b1, b2, ... bn)
--a[b1, b2, ... bn] | a.opIndexUnary!("--")(b1, b2, ... bn)

Overloading Slice Unary Operators

Overloadable Slice Unary Operators
op | rewrite
-a[i..j] | a.opSliceUnary!("-")(i, j)
+a[i..j] | a.opSliceUnary!("+")(i, j)
~a[i..j] | a.opSliceUnary!("~")(i, j)
*a[i..j] | a.opSliceUnary!("*")(i, j)
++a[i..j] | a.opSliceUnary!("++")(i, j)
--a[i..j] | a.opSliceUnary!("--")(i, j)
-a[ ] | a.opSliceUnary!("-")()
+a[ ] | a.opSliceUnary!("+")()
~a[ ] | a.opSliceUnary!("~")()
*a[ ] | a.opSliceUnary!("*")()
++a[ ] | a.opSliceUnary!("++")()
--a[ ] | a.opSliceUnary!("--")()

Cast Operator Overloading

Cast Operators
op | rewrite
cast(type)e | e.opCast!(type)()

Boolean Operations

Notably absent from the list of overloaded unary operators is the ! logical negation operator. More obscurely absent is a unary operator to convert to a bool result. Instead, these are covered by a rewrite to:

opCast!(bool)(e)

So,

if (e)   =>  if (e.opCast!(bool))
if (!e)  =>  if (!e.opCast!(bool))

etc., whenever a bool result is expected. This only happens, however, for instances of structs. Class references are converted to bool by checking to see if the class reference is null or not.

Binary Operator Overloading

The following binary operators are overloadable:

Overloadable Binary Operators
+ | - | * | / | % | ^^ | &
| | ^ | << | >> | >>> | ~ | in

The expression:

a op b

is rewritten as both:

a.opBinary!("op")(b)
b.opBinaryRight!("op")(a)

and the one with the ‘better’ match is selected. It is an error for both to equally match.

Overloading == and !=

Expressions of the form a != b are rewritten as !(a == b).

Given a == b :

  1. If a and b are both class objects, then the expression is rewritten as:
    .object.opEquals(a, b)
    and that function is implemented as:
    bool opEquals(Object a, Object b) {
    if (a is b) return true;
    if (a is null || b is null) return false;
    if (typeid(a) == typeid(b)) return a.opEquals(b);
    return a.opEquals(b) && b.opEquals(a);
}
  2. Otherwise the expressions a.opEquals(b) and b.opEquals(a) are tried. If both resolve to the same opEquals function, then the expression is rewritten to be a.opEquals(b).
  3. If one is a better match then the other, or one compiles and the other does not, the one is selected.
  4. Otherwise, an error results.

If overridding Object.opEquals() for classes, the class member function signature should look like:

class C {
    override bool opEquals(Object o) { ... }
}

If structs declare an opEquals member function, it should follow the following form:

struct S {
    int opEquals(ref const S s) { ... }
}

Overloading < <=, > and >=

Comparison operations are rewritten as follows:

Overloadable Unary Operators
comparison | rewrite 1 | rewrite 2
a < b | a.opCmp(b) < 0 | b.opCmp(a) > 0
a <= b | a.opCmp(b) <= 0 | b.opCmp(a) >= 0
a > b | a.opCmp(b) > 0 | b.opCmp(a) < 0
a >= b | a.opCmp(b) >= 0 | b.opCmp(a) <= 0

Both rewrites are tried. If only one compiles, that one is taken. If they both resolve to the same function, the first rewrite is done. If they resolve to different functions, the best matching one is used. If they both match the same, but are different functions, an ambiguity error results.

If overriding Object.opCmp() for classes, the class member function signature should look like:

class C {
    override int opCmp(Object o) { ... }
}

If structs declare an opCmp member function, it should follow the following form:

struct S {
    int opCmp(ref const S s) { ... }
}

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.

Assignment Operator Overloading

The assignment operator = can be overloaded if the lvalue is a struct 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.

Index Assignment Operator Overloading

If the left hand side of an assignment is an index operation on a struct or class instance, it can be overloaded by providing an opIndexAssign member function. Expressions of the form a[b1, b2, ... bn] = c are rewritten as a.opIndexAssign(c, b1, b2, ... bn).

struct A
{
    int opIndexAssign(int value, size_t i1, size_t i2);
}

void test()
{   A a;

    a[i,3] = 7;		// same as a.opIndexAssign(7,i,3);
}

Slice Assignment Operator Overloading

If the left hand side of an assignment is a slice operation on a struct or class instance, it can be overloaded by providing an opSliceAssign member function. Expressions of the form a[i..j] = c are rewritten as a.opSliceAssign(c, i, j), and a[] = c as a.opSliceAssign(c).

struct A
{
    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;
    int v;

    a[] = v;		// same as a.opSliceAssign(v);
    a[3..4] = v;	// same as a.opSliceAssign(v,3,4);
}

Op Assignment Operator Overloading

The following op assignment operators are overloadable:

Overloadable Op Assignment Operators
+= | -= | *= | /= | %= | ^^= | &=
|= | ^= | <<= | >>= | >>>= | ~= |

The expression:

a op= b

is rewritten as:

a.opOpAssign!("op")(b)

Index Op Assignment Operator Overloading

If the left hand side of an op= is an index expression on a struct or class instance and opIndexOpAssign is a member:

a[b1, b2, ... bn] op= c

it is rewritten as:

a.opIndexOpAssign!("op")(c, b1, b2, ... bn)

Slice Op Assignment Operator Overloading

If the left hand side of an op= is a slice expression on a struct or class instance and opSliceOpAssign is a member:

a[i..j] op= c

it is rewritten as:

a.opSliceOpAssign!("op")(c, i, j)

and

a[] op= c

it is rewritten as:

a.opSliceOpAssign!("op")(c)

Index Operator Overloading

The array index operator, a[b1, b2, ... bn], can be overloaded by declaring a function named opIndex with one or more parameters.

struct A
{
    int opIndex(size_t i1, size_t i2, size_t i3);
}

void test()
{   A a;
    int i;

    i = a[5,6,7];	// same as i = a.opIndex(5,6,7);
}

In this way a struct or class object can behave as if it were an array.

If an index expression can be rewritten using opIndexAssign or opIndexOpAssign, those are preferred over opIndex.

Slice Operator Overloading

Overloading the slicing operator means overloading expressions like a[] and a[i..j]. This can be done by declaring a member function named opSlice.

class A
{
    int opSlice();		 		  // overloads a[]
    int opSlice(size_t x, size_t y);		  // overloads a[i .. j]
}

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);
}

If a slice expression can be rewritten using opSliceAssign or opSliceOpAssign, those are preferred over opSlice.

Forwarding

Member names not found in a class or struct can be forwarded to a template function named opDispatch for resolution.

import std.stdio;

struct S
{
    void opDispatch(string s, T)(T i)
    {
    writefln("S.opDispatch('%s', %s)", s, i);
    }
}

class C
{
    void opDispatch(string s)(int i)
    {
    writefln("C.opDispatch('%s', %s)", s, i);
    }
}

struct D
{
    template opDispatch(string s)
    {
    enum int opDispatch = 8;
    }
}

void main()
{
    S s;
    s.opDispatch!("hello")(7);
    s.foo(7);

    auto c = new C();
    c.foo(8);

    D d;
    writefln("d.foo = %s", d.foo);
    assert(d.foo == 8);
}

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


Templates

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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 ) Constraintopt
        { DeclDefs }

TemplateIdentifier:
    Identifier

TemplateParameterList:
    TemplateParameter
        TemplateParameter ,
    TemplateParameter , TemplateParameterList

TemplateParameter:
    TemplateTypeParameter
    TemplateValueParameter
    TemplateAliasParameter
    TemplateTupleParameter
        TemplateThisParameter

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 )
        TemplateIdentifier ! TemplateSingleArgument

TemplateArgumentList:
    TemplateArgument
        TemplateArgument ,
    TemplateArgument , TemplateArgumentList

TemplateArgument:
    Type
    AssignExpression
    Symbol

Symbol:
    SymbolTail
    . SymbolTail

SymbolTail:
    Identifier
    Identifier . SymbolTail
    TemplateInstance
    TemplateInstance . SymbolTail

TemplateSingleArgument:
    Identifier
    BasicTypeX
    CharacterLiteral
    StringLiteral
    IntegerLiteral
    FloatLiteral
    true
    false
    null
    __FILE__
    __LINE__

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*

If the TemplateArgument is one token long, the parentheses can be omitted:

TFoo!int.t x;   // same as TFoo!(int).t x;

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 This Parameters

TemplateThisParameter:
    this TemplateTypeParameter

TemplateThisParameters are used in member function templates to pick up the type of the this reference.

import std.stdio;

struct S
{
    const void foo(this T)(int i)
    {
    writeln(typeid(T));
    }
}

void main()
{
    const(S) s;
    (&s).foo(1);
    S s2;
    s2.foo(2);
    immutable(S) s3;
    s3.foo(3);
}

Prints:

const(S)
S
immutable(S)

Template Value Parameters

TemplateValueParameter:
    BasicType Declarator
    BasicType Declarator TemplateValueParameterSpecialization
    BasicType Declarator TemplateValueParameterDefault
    BasicType Declarator TemplateValueParameterSpecialization TemplateValueParameterDefault

TemplateValueParameterSpecialization:
    : ConditionalExpression

TemplateValueParameterDefault:
    = __FILE__
    = __LINE__
    = AssignExpression

The __FILE__ and __LINE__ expand to the source file name and line number at the point of instantiation.

Template value parameter types can be any type which can be statically initialized at compile time, and the value argument can be any expression which can be evaluated at compile time. This includes integers, floating point types, and strings.

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. Literals can also be used as arguments to alias parameters.

  • 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
}
  • Literals

template Foo(alias X, alias Y)
{
    static int i = X;
    static string s = Y;
}

void test()
{
    alias Foo!(3, "bar") foo;
    writeln(foo.i, foo.s);  // prints 3bar
}

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 and structs.

Class Templates

ClassTemplateDeclaration:
    class Identifier ( TemplateParameterList ) Constraintopt BaseClassList 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 ) Constraintopt StructBody

UnionTemplateDeclaration:
    union Identifier ( TemplateParameterList ) Constraintopt StructBody

InterfaceTemplateDeclaration:
    interface Identifier ( TemplateParameterList ) Constraintopt BaseInterfaceList 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 can have their return types deduced based on the first ReturnStatement in the function:

auto Square(T)(T t)
{
    return t * t;
}

If there is more than one return statement, then the types of the return statement expressions must match. If there are no return statements, then the return type of the function template is void.

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
}

Template Constraints

Constraint:
    if ( ConstraintExpression )

ConstraintExpression:
    Expression

Constraints are used to impose additional constraints on matching arguments to a template beyond what is possible in the TemplateParameterList. The ConstraintExpression is computed at compile time and returns a result that is converted to a boolean value. If that value is true, then the template is matched, otherwise the template is not matched.

For example, the following function template only matches with odd values of N:

void foo(int N)()
    if (N & 1)
{
    ...
}
...
foo!(3)();  // ok, matches
foo!(4)();  // error, no match

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

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


Mixins

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

Template Mixins

A TemplateMixin takes an arbitrary set of declarations from the body of a TemplateDeclaration and inserts them into the current context.
TemplateMixinDeclaration:
    mixin template TemplateIdentifier ( TemplateParameterList ) Constraintopt
        { 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.

mixin 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:
mixin template Foo(T)
{
    T x = 5;
}

mixin Foo!(int);		// create x of type int
Mixins can add virtual functions to a class:
mixin 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;

mixin 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:
mixin 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:
mixin 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;

mixin 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:
mixin template Foo()
{
    int x = 5;
    void func(int x) { }
}

mixin 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;

mixin template Foo()
{
    int x = 5;
    int y = 7;
    void func() { }
}

mixin 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:

mixin template Foo()
{
    void func(int x) {  }
}

mixin 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;

mixin 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
}

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


Contract Programming

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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

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


Conditional Compilation

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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

Versions enable multiple versions of a module to be implemented with a single source file.

VersionCondition:
    version ( IntegerLiteral )
    version ( Identifier )
    version ( unittest )

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
}

The version(unittest) is satisfied if and only if the code is compiled with unit tests enabled (the -unittest option on dmd).

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 | Digital Mars is the compiler vendor
X86 | Intel and AMD 32 bit processors
X86_64 | AMD and Intel 64 bit processors
Windows | Microsoft Windows systems
Win32 | Microsoft 32 bit Windows systems
Win64 | Microsoft 64 bit Windows systems
linux | All linux systems
D_NET | .NET
OSX | Mac OS X
FreeBSD | FreeBSD
Solaris | Solaris
Posix | All posix systems (includes Linux, FreeBSD, OS X, Solaris, etc.)
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
unittest | Unit tests are enabled (command line switch -unittest)
D_Version2 | This is a D version 2 compiler
none | Never defined; used to just disable a section of code
all | Always defined; used as the opposite of none

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

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.

DebugCondition:
    debug
    debug ( IntegerLiteral )
    debug ( Identifier )

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.

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


Traits

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

Traits

Traits are extensions to the language to enable programs, at compile time, to get at information internal to the compiler. This is also known as compile time reflection. It is done as a special, easily extended syntax (similar to Pragmas) so that new capabilities can be added as required.

TraitsExpression:
    __traits ( TraitsKeyword , TraitsArguments )

TraitsKeyword:
    isAbstractClass
    isArithmetic
    isAssociativeArray
    isFinalClass
    isFloating
    isIntegral
    isScalar
    isStaticArray
    isUnsigned
    isVirtualFunction
    isAbstractFunction
    isFinalFunction
    isStaticFunction
    isRef
    isOut
    isLazy
    hasMember
    identifier
    getMember
    getOverloads
    getVirtualFunctions
    classInstanceSize
    allMembers
    derivedMembers
    isSame
    compiles

TraitsArguments:
    TraitsArgument
    TraitsArgument , TraitsArguments

TraitsArgument:
    AssignExpression
    Type

isArithmetic

If the arguments are all either types that are arithmetic types, or expressions that are typed as arithmetic types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

void main()
{
    int i;
    writefln(__traits(isArithmetic, int));
    writefln(__traits(isArithmetic, i, i+1, int));
    writefln(__traits(isArithmetic));
    writefln(__traits(isArithmetic, int*));
}

Prints:

true
true
false
false

isFloating

Works like isArithmetic, except it's for floating point types (including imaginary and complex types).

isIntegral

Works like isArithmetic, except it's for integral types (including character types).

isScalar

Works like isArithmetic, except it's for scalar types.

isUnsigned

Works like isArithmetic, except it's for unsigned types.

isStaticArray

Works like isArithmetic, except it's for static array types.

isAssociativeArray

Works like isArithmetic, except it's for associative array types.

isAbstractClass

If the arguments are all either types that are abstract classes, or expressions that are typed as abstract classes, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

abstract class C { int foo(); }

void main()
{
    C c;
    writefln(__traits(isAbstractClass, C));
    writefln(__traits(isAbstractClass, c, C));
    writefln(__traits(isAbstractClass));
    writefln(__traits(isAbstractClass, int*));
}

Prints:

true
true
false
false

isFinalClass

Works like isAbstractClass, except it's for final classes.

isVirtualFunction

Takes one argument. If that argument is a virtual function, true is returned, otherwise false.

import std.stdio;

struct S
{
  void bar() { }
}

class C
{
  void bar() { }
}

void main()
{
    writefln(__traits(isVirtualFunction, C.bar));  // true
    writefln(__traits(isVirtualFunction, S.bar));  // false
}

isAbstractFunction

Takes one argument. If that argument is an abstract function, true is returned, otherwise false.

import std.stdio;

struct S
{
  void bar() { }
}

class C
{
  void bar() { }
}

class AC
{
  abstract void foo();
}

void main()
{
    writefln(__traits(isAbstractFunction, C.bar));   // false
    writefln(__traits(isAbstractFunction, S.bar));   // false
    writefln(__traits(isAbstractFunction, AC.foo));  // true
}

isFinalFunction

Takes one argument. If that argument is a final function, true is returned, otherwise false.

import std.stdio;

struct S
{
  void bar() { }
}

class C
{
  void bar() { }
  final void foo();
}

final class FC
{
  void foo();
}

void main()
{
    writefln(__traits(isFinalFunction, C.bar));	  // false
    writefln(__traits(isFinalFunction, S.bar));	  // false
    writefln(__traits(isFinalFunction, C.foo));	  // true
    writefln(__traits(isFinalFunction, FC.foo));  // true
}

isStaticFunction

Takes one argument. If that argument is a static function, meaning it has no context pointer, true is returned, otherwise false.

isRef, isOut, isLazy

Takes one argument. If that argument is a declaration, true is returned if it is ref, out, lazy, otherwise false.

void fooref(ref int x)
{
    static assert(__traits(isRef, x));
    static assert(!__traits(isOut, x));
    static assert(!__traits(isLazy, x));
}

void fooout(out int x)
{
    static assert(!__traits(isRef, x));
    static assert(__traits(isOut, x));
    static assert(!__traits(isLazy, x));
}

void foolazy(lazy int x)
{
    static assert(!__traits(isRef, x));
    static assert(!__traits(isOut, x));
    static assert(__traits(isLazy, x));
}

hasMember

The first argument is a type that has members, or is an expression of a type that has members. The second argument is a string. If the string is a valid property of the type, true is returned, otherwise false.

import std.stdio;

struct S
{
    int m;
}

void main()
{   S s;

    writefln(__traits(hasMember, S, "m")); // true
    writefln(__traits(hasMember, s, "m")); // true
    writefln(__traits(hasMember, S, "y")); // false
    writefln(__traits(hasMember, int, "sizeof")); // true
}

identifier

Takes one argument, a symbol. Returns the identifier for that symbol as a string literal.

getMember

Takes two arguments, the second must be a string. The result is an expression formed from the first argument, followed by a ‘.’, followed by the second argument as an identifier.

import std.stdio;

struct S
{
    int mx;
    static int my;
}

void main()
{ S s;

  __traits(getMember, s, "mx") = 1;  // same as s.mx=1;
  writefln(__traits(getMember, s, "m" ~ "x")); // 1

  __traits(getMember, S, "mx") = 1;  // error, no this for S.mx
  __traits(getMember, S, "my") = 2;  // ok
}

getOverloads

The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is an array of all the overloads of that function.

import std.stdio;

class D
{
    this() { }
    ~this() { }
    void foo() { }
    int foo(int) { return 2; }
}

void main()
{
    D d = new D();

    foreach (t; __traits(getOverloads, D, "foo"))
    writefln(typeid(typeof(t)));

    alias typeof(__traits(getOverloads, D, "foo")) b;
    foreach (t; b)
    writefln(typeid(t));

    auto i = __traits(getOverloads, d, "foo")[1](1);
    writefln(i);
}

Prints:

void()
int()
void()
int()
2

getVirtualFunctions

The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is an array of the virtual overloads of that function.

import std.stdio;

class D
{
    this() { }
    ~this() { }
    void foo() { }
    int foo(int) { return 2; }
}

void main()
{
    D d = new D();

    foreach (t; __traits(getVirtualFunctions, D, "foo"))
    writefln(typeid(typeof(t)));

    alias typeof(__traits(getVirtualFunctions, D, "foo")) b;
    foreach (t; b)
    writefln(typeid(t));

    auto i = __traits(getVirtualFunctions, d, "foo")[1](1);
    writefln(i);
}

Prints:

void()
int()
void()
int()
2

classInstanceSize

Takes a single argument, which must evaluate to either a class type or an expression of class type. The result is of type size_t, and the value is the number of bytes in the runtime instance of the class type. It is based on the static type of a class, not the polymorphic type.

allMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type combined with all of the members of the base classes (if the type is a class). No name is repeated. Builtin properties are not included.

import std.stdio;

class D
{
    this() { }
    ~this() { }
    void foo() { }
    int foo(int) { return 0; }
}

void main()
{
    auto a = __traits(allMembers, D);
    writefln(a);
    // _ctor,_dtor,foo,print,toString,toHash,opCmp,opEquals

    auto b = [ __traits(allMembers, D) ];
    writefln(b);
    // [_ctor,_dtor,foo,print,toString,toHash,opCmp,opEquals]
}

The order in which the strings appear in the result is not defined.

derivedMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type. No name is repeated. Base class member names are not included. Builtin properties are not included.

import std.stdio;

class D
{
    this() { }
    ~this() { }
    void foo() { }
    int foo(int) { return 0; }
}

void main()
{
    auto a = __traits(derivedMembers, D);
    writefln(a);	// _ctor,_dtor,foo
}

The order in which the strings appear in the result is not defined.

isSame

Takes two arguments and returns bool true if they are the same symbol, false if not.

import std.stdio;

struct S { }

int foo();
int bar();

void main()
{
    writefln(__traits(isSame, foo, foo)); // true
    writefln(__traits(isSame, foo, bar)); // false
    writefln(__traits(isSame, foo, S));   // false
    writefln(__traits(isSame, S, S));     // true
    writefln(__traits(isSame, std, S));   // false
    writefln(__traits(isSame, std, std)); // true
}

If the two arguments are expressions made up of literals or enums that evaluate to the same value, true is returned.

compiles

Returns a bool true if all of the arguments compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. The arguments cannot be statements or declarations.

If there are no arguments, the result is false.

import std.stdio;

struct S
{
    static int s1;
    int s2;
}

int foo();
int bar();

void main()
{
    writefln(__traits(compiles));                      // false
    writefln(__traits(compiles, foo));                 // true
    writefln(__traits(compiles, foo + 1));             // true
    writefln(__traits(compiles, &foo + 1));            // false
    writefln(__traits(compiles, typeof(1)));           // true
    writefln(__traits(compiles, S.s1));                // true
    writefln(__traits(compiles, S.s3));                // false
    writefln(__traits(compiles, 1,2,3,int,long,std));  // true
    writefln(__traits(compiles, 3[1]));                // false
    writefln(__traits(compiles, 1,2,3,int,long,3[1])); // false
}

This is useful for:

  • Giving better error messages inside generic code than the sometimes hard to follow compiler ones.
  • Doing a finer grained specialization than template partial specialization allows for.

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


Errors

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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.

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


Unit Tests

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

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.

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


Garbage Collection

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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
  • Taking the address of (i.e. making a delegate) a nested function that accesses variables in an outer scope
  • A function literal that access variables in an outer scope
  • An AssertExpression that fails its condition

References

  • Wikipedia
  • GC FAQ
  • Uniprocessor Garbage Collector Techniques
  • Garbage Collection : Algorithms for Automatic Dynamic Memory Management

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


Floating Point

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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.

If the floating-point rounding mode is changed within a function, it must be restored before the function exits. If this rule is violated (for example, by the use of inline asm), the rounding mode used for subsequent calculations is undefined.

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.

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


Inline Assembler

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

D x86 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
{
    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

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


Documentation Generator

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Mon Dec 6 11:24:02 2010

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 with at least three hyphens in them 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:
 *

 *      <li> <a href="http://www.digitalmars.com">Digital Mars</a> </li>
 *      <li> <a href="http://www.classicempire.com">Empire</a> </li>
 *

 */

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
  • Postblits
  • 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.

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


Interfacing to C

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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 type modifiers in D. These are handled by 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 type | C type
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
ulong | unsigned long 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

These equivalents hold for most 32 bit C compilers. The C standard does not pin down the sizes of the types, so some care is needed.

Passing D Array Arguments to C Functions

In C, arrays are passed to functions as pointers even if the function prototype says its an array. In D, static arrays are passed by value, not by reference. Thus, the function prototype must be adjusted to match what C expects.

D And C Function Prototype Equivalence
D type | C type
T* | T[]
ref T[dim] | T[dim]

For example:

void foo(int a[3]) { ... } // C code

extern (C)
{
  void foo(ref int[3] a); // D prototype
}

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 perfectly:

void foo(char[] string)
{
    printf("my string is: %.*s\n", string);
}

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. htod will convert bit fields to inline functions that do the right shift and masks.

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


Interfacing to C++

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Interfacing to C++

While D is fully capable of interfacing to C, its ability to interface to C++ is much more limited. There are three ways to do it:

  1. Use C++'s ability to create a C interface, and then use D's ability to interface with C to access that interface.
  2. Use C++'s ability to create a COM interface, and then use D's ability to interface with COM to access that interface.
  3. Use the limited ability described here to connect directly to C++ functions and classes.

The General Idea

Being 100% compatible with C++ means more or less adding a fully functional C++ compiler front end to D. Anecdotal evidence suggests that writing such is a minimum of a 10 man-year project, essentially making a D compiler with such capability unimplementable. Other languages looking to hook up to C++ face the same problem, and the solutions have been:

  1. Support the COM interface (but that only works for Windows).
  2. Laboriously construct a C wrapper around the C++ code.
  3. Use an automated tool such as SWIG to construct a C wrapper.
  4. Reimplement the C++ code in the other language.
  5. Give up.

D takes a pragmatic approach that assumes a couple modest accommodations can solve a significant chunk of the problem:

  • matching C++ name mangling conventions
  • matching C++ function calling conventions
  • matching C++ virtual function table layout for single inheritance

Calling C++ Global Functions From D

Given a C++ function in a C++ source file:

#include <iostream>

using namespace std;

int foo(int i, int j, int k)
{
    cout << "i = " << i << endl;
    cout << "j = " << j << endl;
    cout << "k = " << k << endl;

    return 7;
}

In the corresponding D code, foo is declared as having C++ linkage and function calling conventions:

extern (C++) int foo(int i, int j, int k);

and then it can be called within the D code:

extern (C++) int foo(int i, int j, int k);

void main()
{
    foo(1,2,3);
}

Compiling the two files, the first with a C++ compiler, the second with a D compiler, linking them together, and then running it yields:

i = 1
j = 2
k = 3

There are several things going on here:

  • D understands how C++ function names are "mangled" and the correct C++ function call/return sequence.
  • Because modules are not part of C++, each function with C++ linkage must be globally unique within the program.
  • There are no __cdecl, __far, __stdcall, __declspec, or other such nonstandard C++ extensions in D.
  • There are no volatile type modifiers in D.
  • 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++ functions that reside in namespaces cannot be direcly called from D.

Calling Global D Functions From C++

To make a D function accessible from C++, give it C++ linkage:

import std.stdio;

extern (C++) int foo(int i, int j, int k)
{
    writefln("i = %s", i);
    writefln("j = %s", j);
    writefln("k = %s", k);
    return 1;
}

extern (C++) void bar();

void main()
{
    bar();
}

The C++ end looks like:

int foo(int i, int j, int k);

void bar()
{
    foo(6, 7, 8);
}

Compiling, linking, and running produces the output:

i = 6
j = 7
k = 8

Classes

D classes are singly rooted by Object, and have an incompatible layout from C++ classes. D interfaces, however, are very similar to C++ single inheritance class heirarchies. So, a D interface with the attribute of extern (C++) will have a virtual function pointer table (vtbl[]) that exactly matches C++'s. A regular D interface has a vtbl[] that differs in that the first entry in the vtbl[] is a pointer to D's RTTI info, whereas in C++ the first entry points to the first virtual function.

Calling C++ Virtual Functions From D

Given C++ source code defining a class like:

#include <iostream>

using namespace std;

class D
{
  public:
    virtual int bar(int i, int j, int k)
    {
    cout << "i = " << i << endl;
    cout << "j = " << j << endl;
    cout << "k = " << k << endl;
    return 8;
    }
};

D *getD()
{
    D *d = new D();
    return d;
}

We can get at it from D code like:

extern (C++)
{
  interface D
  {
    int bar(int i, int j, int k);
  }

  D getD();
}

void main()
{
    D d = getD();
    d.bar(9,10,11);
}

Calling D Virtual Functions From C++

Given D code like:

extern (C++) int callE(E);

extern (C++) interface E
{
    int bar(int i, int j, int k);
}

class F : E
{
    extern (C++) int bar(int i, int j, int k)
    {
    writefln("i = ", i);
    writefln("j = ", j);
    writefln("k = ", k);
    return 8;
    }
}

void main()
{
    F f = new F();
    callE(f);
}

The C++ code to access it looks like:

class E
{
  public:
    virtual int bar(int i, int j, int k);
};

int callE(E *e)
{
    return e->bar(11,12,13);
}

Note:

  • non-virtual functions, and static member functions, cannot be accessed.
  • class fields can only be accessed via virtual getter and setter methods.

Function Overloading

C++ and D follow different rules for function overloading. D source code, even when calling extern (C++) functions, will still follow D overloading rules.

Storage Allocation

C++ code explicitly manages memory with calls to ::operator new() and ::operator delete(). D allocates memory using the D garbage collector, so no explicit delete's are necessary. D's new and delete are not compatible with C++'s ::operator new and ::operator delete. Attempting to allocate memory with C++ ::operator new and deallocate it with D's delete, or vice versa, will result in miserable failure.

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 type | C type
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
ulong | unsigned long long
float | float
double | double
real | long double
ifloat | no equivalent
idouble | no equivalent
ireal | no equivalent
cfloat | no equivalent
cdouble | no equivalent
creal | no equivalent
struct | struct
union | union
enum | enum
class | no equivalent
type* | type *
no equivalent | 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

These equivalents hold for most 32 bit C++ compilers. The C++ standard does not pin down the sizes of the types, so some care is needed.

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. htod will convert bit fields to inline functions that do the right shift and masks.

Object Construction and Destruction

Similarly to storage allocation and deallocation, objects constructed in D code should be destructed in D, and objects constructed in C++ should be destructed in C++ code.

Special Member Functions

D cannot call C++ special member functions, and vice versa. These include constructors, destructors, conversion operators, operator overloading, and allocators.

Runtime Type Identification

D runtime type identification uses completely different techniques than C++. The two are incompatible.

C++ Class Objects by Value

D can access POD (Plain Old Data) C++ structs, and it can access C++ class virtual functions by reference. It cannot access C++ classes by value.

C++ Templates

D templates have little in common with C++ templates, and it is very unlikely that any sort of reasonable method could be found to express C++ templates in a link-compatible way with D.

This means that the C++ STL, and C++ Boost, likely will never be accessible from D.

Exception Handling

D and C++ exception handling are completely different. Throwing exceptions across the boundaries between D and C++ code will likely not work.

Future Developments

How the upcoming C++0x standard will affect this is not known.

Over time, more aspects of the C++ ABI may be accessible directly from D.

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


Portability

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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.

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


Embedding D in HTML

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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;
}

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


Named Character Entities

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

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 | ♦

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


Memory-Safe-D-Spec

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

The Memory Safe D Spec

Memory Safety for a program is defined as it being impossible for the program to corrupt memory. Therefore, the Safe D consists only of programming language features that are guaranteed to never result in memory corruption.

Safe D is enabled on a per-module basis by compiling with the -safe compiler switch.

Proscribed Forms

  • Inline assembler.
  • Casting away const or immutable attributes.
  • Casting away shared attributes.
  • Casting from one pointer type to another pointer type, except for:
    • casting to void* is allowed
    • casting from a pointer to an arithmetic type to a pointer to another arithmetic type of the same or smaller size is allowed
  • Casting from a non-pointer type to a pointer type.

A safe module can import and use the public interface of a system module.

Limitations

Safe D does not imply that code is portable, uses only sound programming practices, is free of byte order dependencies, or other bugs. It is focussed only on eliminating memory corruption possibilities.

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


Application Binary Interface

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:40 2010

D 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 TypeInfo
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.

A C++ interface differs from a regular interface in that it matches the layout of a C++ class using single inheritance on the target machine.

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 rt/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...

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 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
    TypeNewArray
    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

TypeNewArray:
    Ne Type

TypeStaticArray:
    G Number Type

TypeAssocArray:
    H Type Type

TypePointer:
    P Type

TypeFunction:
    CallConvention FuncAttrs Arguments ArgClose Type

CallConvention:
    F       // D
    U       // C
    W       // Windows
    V       // Pascal
    R       // C++

FuncAttrs:
    FuncAttr
    FuncAttr FuncAttrs

FuncAttr:
    empty
    FuncAttrPure
    FuncAttrNothrow
    FuncAttrProperty
    FuncAttrRef
    FuncAttrTrusted
    FuncAttrSafe

FuncAttrPure:
    Na

FuncAttrNothrow:
    Nb

FuncAttrRef:
    Nc

FuncAttrProperty:
    Nd

FuncAttrTrusted:
    Ne

FuncAttrSafe:
    Nf

Arguments:
    Argument
    Argument Arguments

Argument:
    Argument2
    M Argument2     // scope

Argument2:
    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) calling convention matches the C calling convention used by the supported C compiler on the host system. The extern (D) calling convention for 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.
  • References are returned as pointers in EAX.
  • 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.

Function Attributes

Na
pure
Nb
nothrow

Exception Handling

Windows

Conforms to the Microsoft Windows Structured Exception Handling conventions.

Linux and OSX

Uses static address range/handler tables. It is not compatible with the ELF exception handling tables. The stack is walked assuming it uses the EBP stack frame convention. The EBP convention must be used for every function that has an associated EH 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
OSX | __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 from EBP
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 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

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.

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


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.bigint
Arbitrary-precision ('bignum') arithmetic
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.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-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


object

Forms the symbols available to all D programs. Includes Object, which is the root of the class object hierarchy. This module is implicitly imported.

License:
Boost License 1.0.

Authors:
Walter Bright, Sean Kelly

class Object;
All D class objects inherit from Object.

string 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

equals_t opEquals(Object o);
Returns !=0 if this object does have the same contents as obj.

static Object factory(string classname);
Create instance of class specified by classname. The class must either have no constructors or have a default constructor.

Returns:
null if failed

bool opEquals(Object lhs, Object rhs);
Returns true if lhs and rhs are equal.

struct Interface;
Information about an interface. When an object is accessed via an interface, an Interface* appears as the first entry in its vtbl.

TypeInfo_Class classinfo;
.classinfo for this interface (not for containing class)

ptrdiff_t offset;
offset to Interface 'this' from Object 'this'

alias 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[].

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(in void* p);
Returns a hash of the instance of a type.

equals_t equals(in void* p1, in void* p2);
Compares two instances for equality.

int compare(in void* p1, in 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, null if default initialize to 0

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

void destroy(void* p);
Run the destructor on the object and all its sub-objects

void postblit(void* p);
Run the postblit on the object and all its sub-objects

size_t talign();
Return alignment of type

class TypeInfo_Class: object.TypeInfo;
Runtime type information about a class. Can be retrieved from an object instance by using the .classinfo property.

byte[] init;
class static initializer (init.length gives size in bytes of class)

string name;
class name

void*[] vtbl;
virtual function pointer table

Interface[] interfaces;
interfaces this class implements

TypeInfo_Class base;
base class

static TypeInfo_Class find(in char[] classname);
Search all modules for TypeInfo_Class corresponding to classname.

Returns:
null if not found

Object create();
Create instance of Object represented by 'this'.

const(MemberInfo[]) getMembers(in char[] name);
Search for all members with the name 'name'. If name[] is null, return all members.

class Throwable;

void rt_setTraceHandler(TraceHandler h);
Overrides the default trace hander with a user-supplied version.

Parameters:
TraceHandler h The new trace handler. Set to null to use the default handler.

TraceHandler rt_getTraceHandler();
Return the current trace handler

Throwable.TraceInfo _d_traceContext(void* ptr = null);
This function will be called when an exception is constructed. The user-supplied trace handler will be called if one has been supplied, otherwise no trace will be generated.

Parameters:
void* ptr A pointer to the location from which to generate the trace, or null if the trace should be generated from within the trace handler itself.

Returns:
An object describing the current calling context or null if no handler is supplied.

void _moduleCtor();
Initialize the modules.

void _checkModCtors();
Check for cycles on module constructors, and establish an order for module constructors.

void _moduleTlsCtor();
Run static constructors for thread local global data.

void _moduleDtor();
Destruct the modules.

alias IMonitor;

size_t capacity(T)(T[] arr);
(Property) Get the current capacity of an array. The capacity is the number of elements that the array can grow to before the array must be extended/reallocated.

size_t reserve(T)(ref T[] arr, size_t newcapacity);
Try to reserve capacity for an array. The capacity is the number of elements that the array can grow to before the array must be extended/reallocated.

The return value is the new capacity of the array (which may be larger than the requested capacity).

void assumeSafeAppend(T)(T[] arr);
Assume that it is safe to append to this array. Appends made to this array after calling this function may append in place, even if the array was a slice of a larger array to begin with.

Use this only when you are sure no elements are in use beyond the array in the memory block. If there are, those elements could be overwritten by appending to this array.

Calling this function, and then using references to data located after the given array results in undefined behavior.

bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2);
Helper function used to see if two containers of different types have the same contents in the same sequence.

Copyright Digital Mars 2000 - 2010. | Page generated by Ddoc.


std.algorithm

Implements algorithms oriented mainly towards processing of sequences. Some functions are semantic equivalents or supersets of those found in the <algorithm> header in Alexander Stepanov's Standard Template Library for C++.

Note:
Many functions in this module are parameterized with a function or a predicate . The predicate may be passed either as a function name, a delegate name, a functor name, or a compile-time string. The string may consist of any legal D expression that uses the symbol a (for unary functions) or the symbols a and b (for binary functions). These names will NOT interfere with other homonym symbols in user code because they are evaluated in a different context. The default for all binary comparison predicates is "a == b" for unordered operations and "a < b" for ordered operations.

Example:
int[] a = ...;
static bool greater(int a, int b)
{
    return a > b;
}
sort!(greater)(a);  // predicate as alias
sort!("a > b")(a);  // predicate as string
                    // (no ambiguity with array name)
sort(a);            // no predicate, "a < b" is implicit

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

template map(fun...)
Implements the homonym function (also known as transform) present in many languages of functional flavor. The call map!(fun)(range) returns a range of which elements are obtained by applying fun(x) left to right for all x in range. The original ranges are not changed. Evaluation is done lazily. The range returned by map caches the last value such that evaluating front multiple times does not result in multiple calls to fun.

Example:
int[] arr1 = [ 1, 2, 3, 4 ];
int[] arr2 = [ 5, 6 ];
auto squares = map!("a * a")(chain(arr1, arr2));
assert(equal(squares, [ 1, 4, 9, 16, 25, 36 ]));
Multiple functions can be passed to map. In that case, the element type of map is a tuple containing one element for each function.

Example:
auto arr1 = [ 1, 2, 3, 4 ];
foreach (e; map!("a + a", "a * a")(arr1))
{
    writeln(e[0], " ", e[1]);
}
You may alias map with some function(s) to a symbol and use it

separately:
alias map!(to!string) stringize;
assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ]));

template reduce(fun...)
Implements the homonym function (also known as accumulate, compress, inject, or foldl) present in various programming languages of functional flavor. The call reduce!(fun)(seed, range) first assigns seed to an internal variable result, also called the accumulator. Then, for each element x in range, result = fun(result, x) gets evaluated. Finally, result is returned. The one-argument version reduce!(fun)(range) works similarly, but it uses the first element of the range as the seed (the range must be non-empty).

Many aggregate range operations turn out to be solved with reduce quickly and easily. The example below illustrates reduce's remarkable power and flexibility.

Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto sum = reduce!("a + b")(0, arr);
assert(sum == 15);

// Compute the maximum of all elements
auto largest = reduce!(max)(arr);
assert(largest == 5);

// Compute the number of odd elements
auto odds = reduce!("a + (b & 1)")(0, arr);
assert(odds == 3);

// Compute the sum of squares
auto ssquares = reduce!("a + b * b")(0, arr);
assert(ssquares == 55);

// Chain multiple ranges into seed
int[] a = [ 3, 4 ];
int[] b = [ 100 ];
auto r = reduce!("a + b")(chain(a, b));
assert(r == 107);

// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = reduce!("a + b")(chain(a, b, c));
assert(r1 == 112.5);
Multiple functions:
Sometimes it is very useful to compute multiple aggregates in one pass. One advantage is that the computation is faster because the looping overhead is shared. That's why reduce accepts multiple functions. If two or more functions are passed, reduce returns a std.typecons.Tuple object with one member per passed-in function. The number of seeds must be correspondingly increased.

Example:
double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ];
// Compute minimum and maximum in one pass
auto r = reduce!(min, max)(a);
// The type of r is Tuple!(double, double)
assert(r[0] == 2);  // minimum
assert(r[1] == 11); // maximum

// Compute sum and sum of squares in one pass
r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a);
assert(r[0] == 35);  // sum
assert(r[1] == 233); // sum of squares
// Compute average and standard deviation from the above
auto avg = r[0] / a.length;
auto stdev = sqrt(r[1] / a.length - avg * avg);

void fill(Range, Value)(Range range, Value filler);
Fills a range with a value.

Example:
int[] a = [ 1, 2, 3, 4 ];
fill(a, 5);
assert(a == [ 5, 5, 5, 5 ]);

void fill(Range1, Range2)(Range1 range, Range2 filler);
Fills range with a pattern copied from filler. The length of range does not have to be a multiple of the length of filler. If filler is empty, an exception is thrown.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
int[] b = [ 8, 9 ];
fill(a, b);
assert(a == [ 8, 9, 8, 9, 8 ]);

void uninitializedFill(Range, Value)(Range range, Value filler);
Fills a range with a value. Assumes that the range does not currently contain meaningful content. This is of interest for structs that define copy constructors (for all other types, fill and uninitializedFill are equivalent).

Example:
struct S { ... }
S[] s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
uninitializedFill(s, 42);
assert(s == [ 42, 42, 42, 42, 42 ]);

void initializeAll(Range)(Range range);
Initializes all elements of a range with their .init value. Assumes that the range does not currently contain meaningful content.

Example:
struct S { ... }
S[] s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5];
initialize(s);
assert(s == [ 0, 0, 0, 0, 0 ]);

template filter(alias pred)
Implements the homonym function present in various programming languages of functional flavor. The call filter!(fun)(range) returns a new range only containing elements x in r for which predicate(x) is true.

Example:
int[] arr = [ 1, 2, 3, 4, 5 ];
// Sum all elements
auto small = filter!("a < 3")(arr);
assert(small == [ 1, 2 ]);
// In combination with chain() to span multiple ranges
int[] a = [ 3, -2, 400 ];
int[] b = [ 100, -101, 102 ];
auto r = filter!("a > 0")(chain(a, b));
assert(equal(r, [ 3, 400, 100, 102 ]));
// Mixing convertible types is fair game, too
double[] c = [ 2.5, 3.0 ];
auto r1 = filter!("cast(int) a != a")(chain(c, a, b));
assert(r1 == [ 2.5 ]);

void move(T)(ref T source, ref T target);
T move(T)(ref T src);
Moves source into target via a destructive copy. Specifically:
  • If hasAliasing!T is true (see std.traits.hasAliasing), then the representation of source is bitwise copied into target and then source = T.init is evaluated.
  • Otherwise, target = source is evaluated.
See also std.contracts.pointsTo.

Preconditions:
&source == &target || !pointsTo(source, source)

Range2 moveAll(Range1, Range2)(Range1 src, Range2 tgt);
For each element a in src and each element b in tgt in lockstep in increasing order, calls move(a, b). Returns the leftover portion of tgt. Throws an exeption if there is not enough room in tgt to acommodate all of src.

Preconditions:
walkLength(src) >= walkLength(tgt)

Tuple!(Range1,Range2) moveSome(Range1, Range2)(Range1 src, Range2 tgt);
For each element a in src and each element b in tgt in lockstep in increasing order, calls move(a, b). Stops when either src or tgt have been exhausted. Returns the leftover portions of the two ranges.

void swap(T)(ref T lhs, ref T rhs);
Swaps lhs and rhs. See also std.exception.pointsTo.

Preconditions:
!pointsTo(lhs, lhs) && !pointsTo(lhs, rhs) && !pointsTo(rhs, lhs) && !pointsTo(rhs, rhs)

struct Splitter(Range,Separator) if (is(typeof(ElementType!(Range).init == Separator.init)) && hasSlicing!(Range));
Splitter!(Range,Separator) splitter(Range, Separator)(Range r, Separator s);
Splits a range using an element as a separator. This can be used with any range type, but is most popular with string types.

Two adjacent separators are considered to surround an empty element in the split range.

If the empty range is given, the result is a range with one empty element. If a range with one separator is given, the result is a range with two empty elements.

Example:
assert(equal(splitter("hello  world", ' '), [ "hello", "", "world" ]));
int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ];
int[][] w = [ [1, 2], [], [3], [4, 5] ];
assert(equal(splitter(a, 0), w));
a = null;
assert(equal(splitter(a, 0), [ (int[]).init ]));
a = [ 0 ];
assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ]));
a = [ 0, 1 ];
assert(equal(splitter(a, 0), [ [], [1] ]));

struct Splitter(Range,Separator) if (is(typeof(Range.init.front == Separator.init.front)));
Splits a range using another range as a separator. This can be used with any range type, but is most popular with string types.

struct Uniq(alias pred,R);
Uniq!(pred,Range) uniq(alias pred = "a == b", Range)(Range r);
Iterates unique consecutive elements of the given range (functionality akin to the uniq system utility). Equivalence of elements is assessed by using the predicate pred, by default "a == b". If the given range is bidirectional, uniq also yields a bidirectional range.

Example:
int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][]));

struct Group(alias pred,R) if (isInputRange!(R));
Group!(pred,Range) group(alias pred = "a == b", Range)(Range r);
Similarly to uniq, group iterates unique consecutive elements of the given range. The element type is Tuple!(ElementType!R, uint) because it includes the count of equivalent elements seen. Equivalence of elements is assessed by using the predicate pred, by default "a == b".

Group is an input range if R is an input range, and a forward range in all other cases.

Example:
int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ];
assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u),
    tuple(4, 3u), tuple(5, 1u) ][]));

R find(alias pred = "a == b", R, E)(R haystack, E needle);
Finds an individual element in an input range. Elements of haystack are compared with needle by using predicate pred. Performs Ο(walkLength(haystack)) evaluations of pred. See also STL's find.

To find the last occurence of needle in haystack, call find(retro(haystack), needle). See also std.range.retro.

Parameters:
haystack | The range searched in.
needle | The element searched for.

Constraints:
isInputRange!R && is(typeof(binaryFun!pred(haystack.front, needle) : bool))

Returns:
haystack advanced such that binaryFun!pred(haystack.front, needle) is true (if no such position exists, returns haystack after exhaustion).

Example:
assert(find("hello, world", ',') == ", world");
assert(find([1, 2, 3, 5], 4) == []);
assert(find(SList!int(1, 2, 3, 4, 5)[], 4) == SList!int(4, 5)[]);
assert(find!"a > b"([1, 2, 3, 5], 2) == [3, 5]);

auto a = [ 1, 2, 3 ];
assert(find(a, 5).empty);       // not found
assert(!find(a, 2).empty);      // found

// Case-insensitive find of a string
string[] s = [ "Hello", "world", "!" ];
assert(!find!("tolower(a) == b")(s, "hello").empty);

R1 find(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
Finds a forward range in another. Elements are compared for equality. Performs Ο(walkLength(haystack) * walkLength(needle)) comparisons in the worst case. Specializations taking advantage of bidirectional or random access (where present) may accelerate search depending on the statistics of the two ranges' content.

Parameters:
haystack | The range searched in.
needle | The range searched for.

Constraints:
isForwardRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack.front, needle.front) : bool))

Returns:
haystack advanced such that needle is a prefix of it (if no such position exists, returns haystack advanced to termination).

assert(find("hello, world", "World").empty);
assert(find("hello, world", "wo") == "world");
assert(find([1, 2, 3, 4], SList!(2, 3)[]) == [2, 3, 4]);

Tuple!(Range,size_t) find(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles);
struct BoyerMooreFinder(alias pred,Range);
BoyerMooreFinder!(binaryFun!(pred),Range) boyerMooreFinder(alias pred = "a == b", Range)(Range needle);
Finds two or more needles into a haystack. The predicate pred is used throughout to compare elements. By default, elements are compared for equality.

Parameters:
haystack | The target of the search. Must be an input range . If any of needles is a range with elements comparable to elements in haystack, then haystack must be a forward range such that the search can backtrack.
needles | One or more items to search for. Each of needles must be either comparable to one element in haystack, or be itself a forward range with elements comparable with elements in haystack.

Returns:
A tuple containing haystack positioned to match one of the needles and also the 1-based index of the matching element in needles (0 if none of needles matched, 1 if needles[0] matched, 2 if needles[1] matched...).

The relationship between haystack and needles simply means that one can e.g. search for individual ints or arrays of ints in an array of ints. In addition, if elements are individually comparable, searches of heterogeneous types are allowed as well: a double[] can be searched for an int or a short[], and conversely a long can be searched for a float or a double[]. This makes for efficient searches without the need to coerce one side of the comparison into the other's side type.

Example:
int[] a = [ 1, 4, 2, 3 ];
assert(find(a, 4) == [ 4, 2, 3 ]);
assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]);
assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2));
// Mixed types allowed if comparable
assert(find(a, 5, [ 1.2, 3.5 ], 2.0, [ 1 ]) == tuple([ 2, 3 ], 3));
The complexity of the search is Ο(haystack.length * max(needles.length)). (For needles that are individual items, length is considered to be 1.) The strategy used in searching several subranges at once maximizes cache usage by moving in haystack as few times as possible.

Range find(alias pred, Range)(Range haystack);
Advances the input range haystack by calling haystack.popFront until either pred(haystack.front), or haystack.empty. Performs Ο(haystack.length) evaluations of pred. See also STL's find_if.

To find the last element of a bidirectional haystack satisfying pred, call find!(pred)(retro(haystack)). See also std.range.retro.

Example:
auto arr = [ 1, 2, 3, 4, 1 ];
assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);

// with predicate alias
bool pred(int x) { return x + 1 > 1.5; }
assert(find!(pred)(arr) == arr);

sizediff_t indexOf(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle);
If haystack supports slicing, returns the smallest number n such that haystack[n .. $].startsWith!pred(needle). Oherwise, returns the smallest n such that after n calls to haystack.popFront, haystack.startsWith!pred(needle). If no such number could be found, return -1.

enum OpenRight;
Interval option specifier for until (below) and others.

no
Interval is closed to the right (last element included)

yes
Interval is open to the right (last element is not included)

struct Until(alias pred,Range,Sentinel) if (isInputRange!(Range));
Until!(pred,Range,Sentinel) until(alias pred = "a == b", Range, Sentinel)(Range range, Sentinel sentinel, OpenRight openRight = OpenRight.yes);
Until!(pred,Range,void) until(alias pred, Range)(Range range, OpenRight openRight = OpenRight.yes);
Lazily iterates range until value sentinel is found, at which point it stops.

Example:
int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5];
assert(equal(a.until(7), [1, 2, 4][]));
assert(equal(a.until(7, OpenRight.no), [1, 2, 4, 7][]));

uint startsWith(alias pred = "a == b", Range, Ranges...)(Range doesThisStart, Ranges withOneOfThese);
bool startsWith(alias pred = "a == b", R1, R2)(R1 doesThisStart, R2 withThis);
bool startsWith(alias pred = "a == b", R, E)(R doesThisStart, E withThis);
If the range doesThisStart starts with any of the withOneOfThese ranges or elements, returns 1 if it starts with withOneOfThese[0], 2 if it starts with withOneOfThese[1], and so on. If no match, returns 0.

Example:
assert(startsWith("abc", ""));
assert(startsWith("abc", "a"));
assert(!startsWith("abc", "b"));
assert(startsWith("abc", 'a', "b") == 1);
assert(startsWith("abc", "b", "a") == 2);
assert(startsWith("abc", "a", "a") == 1);
assert(startsWith("abc", "x", "a", "b") == 2);
assert(startsWith("abc", "x", "aa", "ab") == 3);
assert(startsWith("abc", "x", "aaa", "sab") == 0);
assert(startsWith("abc", "x", "aaa", "a", "sab") == 3);

bool skipOver(alias pred = "a == b", R1, R2)(ref R1 r1, R2 r2);
If startsWith(r1, r2), consume the corresponding elements off r1 and return true. Otherwise, leave r1 unchanged and return false.

bool skipOver(alias pred = "a == b", R, E)(ref R r, E e);
Checks whether a range starts with an element, and if so, consume that element off r and return true. Otherwise, leave r unchanged and return false.

uint endsWith(alias pred = "a == b", Range, Ranges...)(Range doesThisEnd, Ranges withOneOfThese);
The reciprocal of startsWith.

Example:
assert(endsWith("abc", ""));
assert(!endsWith("abc", "b"));
assert(endsWith("abc", "a", 'c') == 2);
assert(endsWith("abc", "c", "a") == 1);
assert(endsWith("abc", "c", "c") == 1);
assert(endsWith("abc", "x", "c", "b") == 2);
assert(endsWith("abc", "x", "aa", "bc") == 3);
assert(endsWith("abc", "x", "aaa", "sab") == 0);
assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3);

uint endsWith(alias pred = "a == b", Range, Elements...)(Range doesThisEnd, Elements withOneOfThese);
Checks whether doesThisEnd starts with one of the individual elements withOneOfThese according to pred.

Example:
assert(endsWith("abc", 'x', 'c', 'a') == 2);

Range findAdjacent(alias pred = "a == b", Range)(Range r);
Advances r until it finds the first two adjacent elements a, b that satisfy pred(a, b). Performs Ο(r.length) evaluations of pred. See also STL's adjacent_find.

Example:
int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ];
auto r = findAdjacent(a);
assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]);
p = findAdjacent!("a < b")(a);
assert(p == [ 7, 8, 9 ]);

Range1 findAmong(alias pred = "a == b", Range1, Range2)(Range1 seq, Range2 choices);
Advances seq by calling seq.popFront until either find!(pred)(choices, seq.front) is true, or seq becomes empty. Performs Ο(seq.length * choices.length) evaluations of pred. See also STL's find_first_of.

Example:
int[] a = [ -1, 0, 1, 2, 3, 4, 5 ];
int[] b = [ 3, 1, 2 ];
assert(findAmong(a, b) == a[2 .. $]);

size_t count(alias pred = "a == b", Range, E)(Range r, E value);
Counts the number of elements x in r for which pred(x, value) is true. pred defaults to equality. Performs Ο(r.length) evaluations of pred.

Example:
int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
assert(count(a, 2) == 3);
assert(count!("a > b")(a, 2) == 5);

size_t count(alias pred = "true", Range)(Range r);
Counts the number of elements x in r for which pred(x) is true. Performs Ο(r.length) evaluations of pred.

Example:
int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
assert(count!("a > 1")(a) == 8);

bool balancedParens(Range, E)(Range r, E lPar, E rPar, size_t maxNestingLevel = size_t.max);
Checks whether r has "balanced parentheses", i.e. all instances of lPar are closed by corresponding instances of rPar. The parameter maxNestingLevel controls the nesting level allowed. The most common uses are the default or 0. In the latter case, no nesting is allowed.

Example:
auto s = "1 + (2 * (3 + 1 / 2)";
assert(!balancedParens(s, '(', ')'));
s = "1 + (2 * (3 + 1) / 2)";
assert(balancedParens(s, '(', ')'));
s = "1 + (2 * (3 + 1) / 2)";
assert(!balancedParens(s, '(', ')', 1));
s = "1 + (2 * 3 + 1) / (2 - 5)";
assert(balancedParens(s, '(', ')', 1));

bool equal(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2);
Returns true if and only if the two ranges compare equal element for element, according to binary predicate pred. The ranges may have different element types, as long as pred(a, b) evaluates to bool for a in r1 and b in r2. Performs Ο(min(r1.length, r2.length)) evaluations of pred. See also STL's equal.

Example:
int[] a = [ 1, 2, 4, 3 ];
assert(!equal(a, a[1..$]));
assert(equal(a, a));

// different types
double[] b = [ 1., 2, 4, 3];
assert(!equal(a, b[1..$]));
assert(equal(a, b));

// predicated: ensure that two vectors are approximately equal
double[] c = [ 1.005, 2, 4, 3];
assert(equal!(approxEqual)(b, c));

MinType!(T1,T2,T) min(T1, T2, T...)(T1 a, T2 b, T xs);
Returns the minimum of the passed-in values. The type of the result is computed by using std.traits.CommonType.

MaxType!(T1,T2,T) max(T1, T2, T...)(T1 a, T2 b, T xs);
Returns the maximum of the passed-in values. The type of the result is computed by using std.traits.CommonType.

Example:
int a = 5;
short b = 6;
double c = 2;
auto d = max(a, b);
assert(is(typeof(d) == int));
assert(d == 6);
auto e = min(a, b, c);
assert(is(typeof(e) == double));
assert(e == 2);

Tuple!(ElementType!(Range),size_t) minCount(alias pred = "a < b", Range)(Range range);
Returns the minimum element of a range together with the number of occurrences. The function can actually be used for counting the maximum or any other ordering predicate (that's why maxCount is not provided).

Example:
int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
// Minimum is 1 and occurs 3 times
assert(minCount(a) == tuple(1, 3));
// Maximum is 4 and occurs 2 times
assert(minCount!("a > b")(a) == tuple(4, 2));

Range minPos(alias pred = "a < b", Range)(Range range);
Returns the position of the minimum element of forward range range, i.e. a subrange of range starting at the position of its smallest element and with the same ending as range. The function can actually be used for counting the maximum or any other ordering predicate (that's why maxPos is not provided).

Example:
int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ];
// Minimum is 1 and first occurs in position 3
assert(minPos(a) == [ 1, 2, 4, 1, 1, 2 ]);
// Maximum is 4 and first occurs in position 2
assert(minPos!("a > b")(a) == [ 4, 1, 2, 4, 1, 1, 2 ]);

Tuple!(Range1,Range2) mismatch(alias pred = "a == b", Range1, Range2)(Range1 r1, Range2 r2);
Sequentially compares elements in r1 and r2 in lockstep, and stops at the first mismatch (according to pred, by default equality). Returns a tuple with the reduced ranges that start with the two mismatched values. Performs Ο(min(r1.length, r2.length)) evaluations of pred. See also STL's mismatch.

Example:
int[]    x = [ 1,  5, 2, 7,   4, 3 ];
double[] y = [ 1., 5, 2, 7.3, 4, 8 ];
auto m = mismatch(x, y);
assert(m[0] == x[3 .. $]);
assert(m[1] == y[3 .. $]);

enum EditOp;
Encodes edit operations necessary to transform one sequence into another. Given sequences s (source) and t (target), a sequence of EditOp encodes the steps that need to be taken to convert s into t. For example, if s = "cat" and "cars", the minimal sequence that transforms s into t is: skip two characters, replace 't' with 'r', and insert an 's'. Working with edit operations is useful in applications such as spell-checkers (to find the closest word to a given misspelled word), approximate searches, diff-style programs that compute the difference between files, efficient encoding of patches, DNA sequence analysis, and plagiarism detection.

none
Current items are equal; no editing is necessary.

substitute
Substitute current item in target with current item in source.

insert
Insert current item from the source into the target.

remove
Remove current item from the target.

size_t levenshteinDistance(alias equals = "a == b", Range1, Range2)(Range1 s, Range2 t);
Returns the Levenshtein distance between s and t. The Levenshtein distance computes the minimal amount of edit operations necessary to transform s into t. Performs Ο(s.length * t.length) evaluations of equals and occupies Ο(s.length * t.length) storage.

Example:
assert(levenshteinDistance("cat", "rat") == 1);
assert(levenshteinDistance("parks", "spark") == 2);
assert(levenshteinDistance("kitten", "sitting") == 3);
// ignore case
assert(levenshteinDistance!("toupper(a) == toupper(b)")
    ("parks", "SPARK") == 2);

Tuple!(size_t,EditOp[]) levenshteinDistanceAndPath(alias equals = "a == b", Range1, Range2)(Range1 s, Range2 t);
Returns the Levenshtein distance and the edit path between s and t.

Example:
string a = "Saturday", b = "Sunday";
auto p = levenshteinDistanceAndPath(a, b);
assert(p[0] == 3);
assert(equal(p[1], "nrrnsnnn"));

Range2 copy(Range1, Range2)(Range1 source, Range2 target);
Copies the content of source into target and returns the remaining (unfilled) part of target. See also STL's copy. If a behavior similar to STL's copy_backward is needed, use copy(retro(source), retro(target)). See also std.range.retro.

Example:
int[] a = [ 1, 5 ];
int[] b = [ 9, 8 ];
int[] c = new int[a.length + b.length + 10];
auto d = copy(b, copy(a, c));
assert(c[0 .. a.length + b.length] == a ~ b);
assert(d.length == 10);
As long as the target range elements support assignment from source range elements, different types of ranges are accepted.

Example:
float[] a = [ 1.0f, 5 ];
double[] b = new double[a.length];
auto d = copy(a, b);
To copy at most n elements from range a to range b, you may want to use copy(take(a, n), b). To copy those elements from range a that satisfy predicate pred to range b, you may want to use copy(filter!(pred)(a), b).

Example:
int[] a = [ 1, 5, 8, 9, 10, 1, 2, 0 ];
auto b = new int[a.length];
auto c = copy(filter!("(a & 1) == 1")(a), b);
assert(b[0 .. $ - c.length] == [ 1, 5, 9, 1 ]);

Tuple!(Range1,Range2) swapRanges(Range1, Range2)(Range1 r1, Range2 r2);
Swaps all elements of r1 with successive elements in r2. Returns a tuple containing the remainder portions of r1 and r2 that were not swapped (one of them will be empty). The ranges may be of different types but must have the same element type and support swapping.

Example:
int[] a = [ 100, 101, 102, 103 ];
int[] b = [ 0, 1, 2, 3 ];
auto c = swapRanges(a[1 .. 3], b[2 .. 4]);
assert(c[0].empty && c[1].empty);
assert(a == [ 100, 2, 3, 103 ]);
assert(b == [ 0, 1, 101, 102 ]);

void reverse(Range)(Range r);
Reverses r in-place. Performs r.length evaluations of swap. See also STL's reverse.

Example:
int[] arr = [ 1, 2, 3 ];
reverse(arr);
assert(arr == [ 3, 2, 1 ]);

size_t bringToFront(Range1, Range2)(Range1 front, Range2 back);
The bringToFront function has considerable flexibility and usefulness. It can rotate elements in one buffer left or right, swap buffers of equal length, and even move elements across disjoint buffers of different types and different lengths.

bringToFront takes two ranges front and back, which may be of different types. Considering the concatenation of front and back one unified range, bringToFront rotates that unified range such that all elements in back are brought to the beginning of the unified range. The relative ordering of elements in front and back, respectively, remains unchanged.

The simplest use of bringToFront is for rotating elements in a buffer. For example:

auto arr = [4, 5, 6, 7, 1, 2, 3];
bringToFront(arr[0 .. 4], arr[4 .. $]);
assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]);
The front range may actually "step over" the back range. This is very useful with forward ranges that cannot compute comfortably right-bounded subranges like arr[0 .. 4] above. In the example below, r2 is a right subrange of r1.

auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3);
auto r1 = list[];
auto r2 = list[]; popFrontN(r2, 4);
assert(equal(r2, [ 1, 2, 3 ]));
bringToFront(r1, r2);
assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ]));
Elements can be swapped across ranges of different types:

auto list = SList!(int)(4, 5, 6, 7);
auto vec = [ 1, 2, 3 ];
bringToFront(list[], vec);
assert(equal(list[], [ 1, 2, 3, 4 ]));
assert(equal(vec, [ 5, 6, 7 ]));
Performs Ο(max(front.length, back.length)) evaluations of swap. See also STL's rotate.

Preconditions:
Either front and back are disjoint, or back is reachable from front and front is not reachable from back.

Returns:
The number of elements brought to the front, i.e., the length of back.

enum SwapStrategy;
Defines the swapping strategy for algorithms that need to swap elements in a range (such as partition and sort). The strategy concerns the swapping of elements that are not the core concern of the algorithm. For example, consider an algorithm that sorts [ "abc", "b", "aBc" ] according to toupper(a) < toupper(b). That algorithm might choose to swap the two equivalent strings "abc" and "aBc". That does not affect the sorting since both [ "abc", "aBc", "b" ] and [ "aBc", "abc", "b" ] are valid outcomes.

Some situations require that the algorithm must NOT ever change the relative ordering of equivalent elements (in the example above, only [ "abc", "aBc", "b" ] would be the correct result). Such algorithms are called stable. If the ordering algorithm may swap equivalent elements discretionarily, the ordering is called unstable.

Yet another class of algorithms may choose an intermediate tradeoff by being stable only on a well-defined subrange of the range. There is no established terminology for such behavior; this library calls it semistable.

Generally, the stable ordering strategy may be more costly in time and/or space than the other two because it imposes additional constraints. Similarly, semistable may be costlier than unstable. As (semi-)stability is not needed very often, the ordering algorithms in this module parameterized by SwapStrategy all choose SwapStrategy.unstable as the default.

unstable
Allows freely swapping of elements as long as the output satisfies the algorithm's requirements.

semistable
In algorithms partitioning ranges in two, preserve relative ordering of elements only to the left of the partition point.

stable
Preserve the relative ordering of elements to the largest extent allowed by the algorithm's requirements.

Range remove(SwapStrategy s = SwapStrategy.stable, Range, Offset...)(Range range, Offset offset);
Eliminates elements at given offsets from range and returns the shortened range. In the simplest call, one element is removed.

int[] a = [ 3, 5, 7, 8 ];
assert(remove(a, 1) == [ 3, 7, 8 ]);
assert(a == [ 3, 7, 8, 8 ]);
In the case above the element at offset 1 is removed and remove returns the range smaller by one element. The original array has remained of the same length because all functions in std.algorithm only change content, not topology. The value 8 is repeated because std.algorithm.move was invoked to move elements around and on integers move simply copies the source to the destination. To replace a with the effect of the removal, simply assign a = remove(a, 1). The slice will be rebound to the shorter array and the operation completes with maximal efficiency.

Multiple indices can be passed into remove. In that case, elements at the respective indices are all removed. The indices must be passed in increasing order, otherwise an exception occurs.

int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
assert(remove(a, 1, 3, 5) ==
    [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
(Note how all indices refer to slots in the original array, not in the array as it is being progressively shortened.) Finally, any combination of integral offsets and tuples composed of two integral offsets can be passed in.

int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 6, 7, 8, 10 ]);
In this case, the slots at positions 1, 3, 4, and 9 are removed from the array. The tuple passes in a range closed to the left and open to the right (consistent with built-in slices), e.g. tuple(3, 5) means indices 3 and 4 but not 5.

If the need is to remove some elements in the range but the order of the remaining elements does not have to be preserved, you may want to pass SwapStrategy.unstable to remove.

int[] a = [ 0, 1, 2, 3 ];
assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
In the case above, the element at slot 1 is removed, but replaced with the last element of the range. Taking advantage of the relaxation of the stability requirement, remove moved elements from the end of the array over the slots to be removed. This way there is less data movement to be done which improves the execution time of the function.

The function remove works on any forward range. The moving strategy is (listed from fastest to slowest):
  • If s == SwapStrategy.unstable && isRandomAccessRange!Range && hasLength!Range, then elements are moved from the end of the range into the slots to be filled. In this case, the absolute minimum of moves is performed.
  • Otherwise, if s == SwapStrategy.unstable && isBidirectionalRange!Range && hasLength!Range, then elements are still moved from the end of the range, but time is spent on advancing between slots by repeated calls to range.popFront.
  • Otherwise, elements are moved incrementally towards the front of range; a given element is never moved several times, but more elements are moved than in the previous cases.

Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range range);
Reduces the length of the bidirectional range range by only keeping elements that satisfy pred. If , elements are moved from the right end of the range over the elements to eliminate. If s = SwapStrategy.stable (the default), elements are moved progressively to front such that their relative order is preserved. Returns the tail portion of the range that was moved.

Example:
int[] a = [ 1, 2, 3, 2, 3, 4, 5, 2, 5, 6 ];
assert(a[0 .. $ - remove!("a == 2")(a).length] == [ 1, 3, 3, 4, 5, 5, 6 ]);

Range partition(alias predicate, SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Partitions a range in two using pred as a predicate. Specifically, reorders the range r = [left, right) using swap such that all elements i for which pred(i) is true come before all elements j for which pred(j) returns false.

Performs Ο(r.length) (if unstable or semistable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap. The unstable version computes the minimum possible evaluations of swap (roughly half of those performed by the semistable version).

See also STL's partition and stable_partition.

Returns:
The right part of r after partitioning.

If ss == SwapStrategy.stable, partition preserves the relative ordering of all elements a, b in r for which pred(a) == pred(b). If ss == SwapStrategy.semistable, partition preserves the relative ordering of all elements a, b in the left part of r for which pred(a) == pred(b).

Example:
auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
auto arr = Arr.dup;
static bool even(int a) { return (a & 1) == 0; }
// Partition arr such that even numbers come first
auto r = partition!(even)(arr);
// Now arr is separated in evens and odds.
// Numbers may have become shuffled due to instability
assert(r == arr[5 .. $]);
assert(count!(even)(arr[0 .. 5]) == 5);
assert(find!(even)(r).empty);

// Can also specify the predicate as a string.
// Use 'a' as the predicate argument name
arr[] = Arr[];
r = partition!(q{(a & 1) == 0})(arr);
assert(r == arr[5 .. $]);

// Now for a stable partition:
arr[] = Arr[];
r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr);
// Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1
assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]);

// In case the predicate needs to hold its own state, use a delegate:
arr[] = Arr[];
int x = 3;
// Put stuff greater than 3 on the left
bool fun(int a) { return a > x; }
r = partition!(fun, SwapStrategy.semistable)(arr);
// Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2
assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]);

bool isPartitioned(alias pred, Range)(Range r);
Returns true if r is partitioned according to predicate pred.

Example:
int[] r = [ 1, 3, 5, 7, 8, 2, 4, ];
assert(isPartitioned!("a & 1")(r));

void topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t nth);
Reorders the range r using swap such that r[nth] refers to the element that would fall there if the range were fully sorted. In addition, it also partitions r such that all elements e1 from r[0] to r[nth] satisfy !less(r[nth], e1), and all elements e2 from r[nth] to r[r.length] satisfy !less(e2, r[nth]). Effectively, it finds the nth smallest (according to less) elements in r. Performs Ο(r.length) (if unstable) or Ο(r.length * log(r.length)) (if stable) evaluations of less and swap. See also STL's nth_element.

Example:
int[] v = [ 25, 7, 9, 2, 0, 5, 21 ];
auto n = 4;
topN!(less)(v, n);
assert(v[n] == 9);
// Equivalent form:
topN!("a < b")(v, n);
assert(v[n] == 9);

BUGS:
Stable topN has not been implemented yet.

void topN(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(Range1 r1, Range2 r2);
Stores the smallest elements of the two ranges in the left-hand range.

SortedRange!(Range,less) sort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Sorts a random-access range according to predicate less. Performs Ο(r.length * log(r.length)) (if unstable) or Ο(r.length * log(r.length) * log(r.length)) (if stable) evaluations of less and swap. See also STL's sort and stable_sort.

Example:
int[] array = [ 1, 2, 3, 4 ];
// sort in descending order
sort!("a > b")(array);
assert(array == [ 4, 3, 2, 1 ]);
// sort in ascending order
sort(array);
assert(array == [ 1, 2, 3, 4 ]);
// sort with a delegate
bool myComp(int x, int y) { return x > y; }
sort!(myComp)(array);
assert(array == [ 4, 3, 2, 1 ]);
// Showcase stable sorting
string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ];
sort!("toupper(a) < toupper(b)", SwapStrategy.stable)(words);
assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]);

void schwartzSort(alias transform, alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r);
Sorts a range using an algorithm akin to the Schwartzian transform, also known as the decorate-sort-undecorate pattern in Python and Lisp. (Not to be confused with the other Schwartz.) This function is helpful when the sort comparison includes an expensive computation. The complexity is the same as that of the corresponding sort, but schwartzSort evaluates transform only r.length times (less than half when compared to regular sorting). The usage can be best illustrated with an example.

Example:
uint hashFun(string) { ... expensive computation ... }
string[] array = ...;
// Sort strings by hash, slow
sort!("hashFun(a) < hashFun(b)")(array);
// Sort strings by hash, fast (only computes arr.length hashes):
schwartzSort!(hashFun, "a < b")(array);
The schwartzSort function might require less temporary data and be faster than the Perl idiom or the decorate-sort-undecorate idiom present in Python and Lisp. This is because sorting is done in-place and only minimal extra data (one array of transformed elements) is created.

To check whether an array was sorted and benefit of the speedup of Schwartz sorting, a function schwartzIsSorted is not provided because the effect can be achieved by calling isSorted!(less)(map!(transform)(r)).

void partialSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range)(Range r, size_t n);
Reorders the random-access range r such that the range r[0 .. mid] is the same as if the entire r were sorted, and leaves the range r[mid .. r.length] in no particular order. Performs Ο(r.length * log(mid)) evaluations of pred. The implementation simply calls topN!(less, ss)(r, n) and then sort!(less, ss)(r[0 .. n]).

Example:
int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ];
partialSort(a, 5);
assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]);

void completeSort(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range1, Range2)(SortedRange!(Range1,less) lhs, Range2 rhs);
Sorts the random-access range chain(lhs, rhs) according to predicate less. The left-hand side of the range lhs is assumed to be already sorted; rhs is assumed to be unsorted. The exact strategy chosen depends on the relative sizes of lhs and rhs. Performs Ο(lhs.length + rhs.length * log(rhs.length)) (best case) to Ο((lhs.length + rhs.length) * log(lhs.length + rhs.length)) (worst-case) evaluations of swap.

Example:
int[] a = [ 1, 2, 3 ];
int[] b = [ 4, 0, 6, 5 ];
completeSort(assumeSorted(a), b);
assert(a == [ 0, 1, 2 ]);
assert(b == [ 3, 4, 5, 6 ]);

bool isSorted(alias less = "a < b", Range)(Range r);
Checks whether a forward range is sorted according to the comparison operation less. Performs Ο(r.length) evaluations of less.

Example:
int[] arr = [4, 3, 2, 1];
assert(!isSorted(arr));
sort(arr);
assert(isSorted(arr));
sort!("a > b")(arr);
assert(isSorted!("a > b")(arr));

void makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index);
void makeIndex(alias less = "a < b", SwapStrategy ss = SwapStrategy.unstable, Range, RangeIndex)(Range r, RangeIndex index);
Computes an index for r based on the comparison less. The index is a sorted array of pointers or indices into the original range. This technique is similar to sorting, but it is more flexible because (1) it allows "sorting" of immutable collections, (2) allows binary search even if the original collection does not offer random access, (3) allows multiple indexes, each on a different predicate, and (4) may be faster when dealing with large objects. However, using an index may also be slower under certain circumstances due to the extra indirection, and is always larger than a sorting-based solution because it needs space for the index in addition to the original collection. The complexity is the same as sort's.

makeIndex overwrites its second argument with the result, but never reallocates it. If the second argument's length is less than that of the range indexed, an exception is thrown.

The first overload of makeIndex writes to a range containing pointers, and the second writes to a range containing offsets. The first overload requires Range to be a forward range, and the latter requires it to be a random-access range.

Example:
immutable(int[]) arr = [ 2, 3, 1, 5, 0 ];
// index using pointers
auto index1 = new immutable(int)*[arr.length];
makeIndex!("a < b")(arr, index1);
assert(isSorted!("*a < *b")(index1));
// index using offsets
auto index2 = new size_t[arr.length];
makeIndex!("a < b")(arr, index2);
assert(isSorted!
    ((size_t a, size_t b){ return arr[a] < arr[b];})
    (index2));

enum SortOutput;
Specifies whether the output of certain algorithm is desired in sorted format.

no
Don't sort output

yes
Sort output

bool canFind(alias pred = "a == b", Range, V)(Range range, V value);
Returns true if and only if value can be found in range. Performs Ο(r.length) evaluations of pred.

bool canFind(alias pred, Range)(Range range);
Returns true if and only if a value v satisfying the predicate pred can be found in the forward range range. Performs Ο(r.length) evaluations of pred.

TRange topNCopy(alias less = "a < b", SRange, TRange)(SRange source, TRange target, SortOutput sorted = SortOutput.no);
Copies the top n elements of the input range source into the random-access range target, where n = target.length. Elements of source are not touched. If sorted is true, the target is sorted. Otherwise, the target respects the heap property.

Example:
int[] a = [ 10, 16, 2, 3, 1, 5, 0 ];
int[] b = new int[3];
topNCopy(a, b, true);
assert(b == [ 0, 1, 2 ]);

struct SetUnion(alias less = "a < b",Rs...) if (allSatisfy!(isInputRange,Rs));
SetUnion!(less,Rs) setUnion(alias less = "a < b", Rs...)(Rs rs);
Lazily computes the union of two or more ranges rs. The ranges are assumed to be sorted by less. Elements in the output are not unique; the length of the output is the sum of the lengths of the inputs. (The length member is offered if all ranges also have length.) The element types of all ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
int[] c = [ 10 ];
assert(setUnion(a, b).length == a.length + b.length);
assert(equal(setUnion(a, b), [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9][]));
assert(equal(setUnion(a, c, b),
    [0, 1, 1, 2, 2, 4, 4, 5, 7, 7, 8, 9, 10][]));

struct SetIntersection(alias less = "a < b",Rs...) if (allSatisfy!(isInputRange,Rs));
SetIntersection!(less,Rs) setIntersection(alias less = "a < b", Rs...)(Rs ranges);
Lazily computes the intersection of two or more input ranges rs. The ranges are assumed to be sorted by less. The element types of all ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
int[] c = [ 0, 1, 4, 5, 7, 8 ];
assert(equal(setIntersection(a, a), a));
assert(equal(setIntersection(a, b), [1, 2, 4, 7][]));
assert(equal(setIntersection(a, b, c), [1, 4, 7][]));

struct SetDifference(alias less = "a < b",R1,R2) if (isInputRange!(R1) && isInputRange!(R2));
SetDifference!(less,R1,R2) setDifference(alias less = "a < b", R1, R2)(R1 r1, R2 r2);
Lazily computes the difference of r1 and r2. The two ranges are assumed to be sorted by less. The element types of the two ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
assert(equal(setDifference(a, b), [5, 9][]));

struct SetSymmetricDifference(alias less = "a < b",R1,R2) if (isInputRange!(R1) && isInputRange!(R2));
SetSymmetricDifference!(less,R1,R2) setSymmetricDifference(alias less = "a < b", R1, R2)(R1 r1, R2 r2);
Lazily computes the symmetric difference of r1 and r2, i.e. the elements that are present in exactly one of r1 and r2. The two ranges are assumed to be sorted by less, and the output is also sorted by less. The element types of the two ranges must have a common type.

Example:
int[] a = [ 1, 2, 4, 5, 7, 9 ];
int[] b = [ 0, 1, 2, 4, 7, 8 ];
assert(equal(setSymmetricDifference(a, b), [0, 5, 8, 9][]));

struct NWayUnion(alias less,RangeOfRanges);
NWayUnion!(less,RangeOfRanges) nWayUnion(alias less = "a < b", RangeOfRanges)(RangeOfRanges ror);
Computes the union of multiple sets. The input sets are passed as a range of ranges and each is assumed to be sorted by less. Computation is done lazily, one union element at a time. The complexity of one popFront operation is Ο(log(ror.length)). However, the length of ror decreases as ranges in it are exhausted, so the complexity of a full pass through NWayUnion is dependent on the distribution of the lengths of ranges contained within ror. If all ranges have the same length n (worst case scenario), the complexity of a full pass through NWayUnion is Ο(n * ror.length * log(ror.length)), i.e., log(ror.length) times worse than just spanning all ranges in turn. The output comes sorted (unstably) by less.

Warning:
Because NWayUnion does not allocate extra memory, it will leave ror modified. Namely, NWayUnion assumes ownership of ror and discretionarily swaps and advances elements of it. If you want ror to preserve its contents after the call, you may want to pass a duplicate to NWayUnion (and perhaps cache the duplicate in between calls).

Example:
double[][] a =
[
    [ 1, 4, 7, 8 ],
    [ 1, 7 ],
    [ 1, 7, 8],
    [ 4 ],
    [ 7 ],
];
auto witness = [
    1, 1, 1, 4, 4, 7, 7, 7, 7, 8, 8
];
assert(equal(nWayUnion(a), witness[]));

void largestPartialIntersection(alias less = "a < b", RangeOfRanges, Range)(RangeOfRanges ror, Range tgt, SortOutput sorted = SortOutput.no);
Given a range of sorted forward ranges ror, copies to tgt the elements that are common to most ranges, along with their number of occurrences. All ranges in ror are assumed to be sorted by less. Only the most frequent tgt.length elements are returned.

Example:
// Figure which number can be found in most arrays of the set of
// arrays below.
double[][] a =
[
    [ 1, 4, 7, 8 ],
    [ 1, 7 ],
    [ 1, 7, 8],
    [ 4 ],
    [ 7 ],
];
auto b = new Tuple!(double, uint)[1];
largestPartialIntersection(a, b);
// First member is the item, second is the occurrence count
assert(b[0] == tuple(7.0, 4u));
7.0 is the correct answer because it occurs in 4 out of the 5 inputs, more than any other number. The second member of the resulting tuple is indeed 4 (recording the number of occurrences of 7.0). If more of the top-frequent numbers are needed, just create a larger tgt range. In the axample above, creating b with length 2 yields tuple(1.0, 3u) in the second position.

The function largestPartialIntersection is useful for e.g. searching an inverted index for the documents most likely to contain some terms of interest. The complexity of the search is Ο(n * log(tgt.length)), where n is the sum of lengths of all input ranges. This approach is faster than keeping an associative array of the occurrences and then selecting its top items, and also requires less memory (largestPartialIntersection builds its result directly in tgt and requires no extra memory).

Warning:
Because largestPartialIntersection does not allocate extra memory, it will leave ror modified. Namely, largestPartialIntersection assumes ownership of ror and discretionarily swaps and advances elements of it. If you want ror to preserve its contents after the call, you may want to pass a duplicate to largestPartialIntersection (and perhaps cache the duplicate in between calls).

void largestPartialIntersectionWeighted(alias less = "a < b", RangeOfRanges, Range, WeightsAA)(RangeOfRanges ror, Range tgt, WeightsAA weights, SortOutput sorted = SortOutput.no);
Similar to largestPartialIntersection, but associates a weight with each distinct element in the intersection.

Example:
// Figure which number can be found in most arrays of the set of
// arrays below, with specific per-element weights
double[][] a =
[
    [ 1, 4, 7, 8 ],
    [ 1, 7 ],
    [ 1, 7, 8],
    [ 4 ],
    [ 7 ],
];
auto b = new Tuple!(double, uint)[1];
double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ];
largestPartialIntersectionWeighted(a, b, weights);
// First member is the item, second is the occurrence count
assert(b[0] == tuple(4.0, 2u));
The correct answer in this case is 4.0, which, although only appears two times, has a total weight 4.6 (three times its weight 2.3). The value 7 is weighted with 1.1 and occurs four times for a total weight 4.4.

Andrei Alexandrescu 2008-. | Page generated by Ddoc.


std.array

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

ForeachType!(Range)[] array(Range)(Range r);
Returns a newly-allocated dynamic array consisting of a copy of the input range, static array, dynamic array, or class or struct with an opApply function r. Note that narrow strings are handled as a special case in an overload.

Example:
auto a = array([1, 2, 3, 4, 5][]);
assert(a == [ 1, 2, 3, 4, 5 ]);

ElementType!(String)[] array(String)(String str);
Convert a narrow string to an array type that fully supports random access. This is handled as a special case and always returns a dchar[], const(dchar)[], or immutable(dchar)[] depending on the constness of the input.

bool empty(T)(in T[] a);
Implements the range interface primitive empty for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.empty is equivalent to empty(array).

Example:
void main()
{
    auto a = [ 1, 2, 3 ];
    assert(!a.empty);
    assert(a[3 .. $].empty);
}

T[] save(T)(T[] a);
Implements the range interface primitive save for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.save is equivalent to save(array).

Example:
void main()
{
    auto a = [ 1, 2, 3 ];
    auto b = a.save;
    assert(b is a);
}

void popFront(A)(ref A a);
Implements the range interface primitive popFront for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.popFront is equivalent to popFront(array).

Example:
void main()
{
    int[] a = [ 1, 2, 3 ];
    a.popFront;
    assert(a == [ 2, 3 ]);
}

void popBack(A)(ref A a);
Implements the range interface primitive popBack for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.popBack is equivalent to popBack(array).

Example:
void main()
{
    int[] a = [ 1, 2, 3 ];
    a.popBack;
    assert(a == [ 1, 2 ]);
}

typeof(A[0]) front(A)(A a);
void front(T)(T[] a, T v);
Implements the range interface primitive front for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.front is equivalent to front(array).

Example:
void main()
{
    int[] a = [ 1, 2, 3 ];
    assert(a.front == 1);
}

typeof(A.init[0]) back(A)(A a);
Implements the range interface primitive back for built-in arrays. Due to the fact that nonmember functions can be called with the first argument using the dot notation, array.back is equivalent to back(array).

Example:
void main()
{
    int[] a = [ 1, 2, 3 ];
    assert(a.back == 3);
}

void insert(T, Range)(ref T[] array, size_t pos, Range stuff);
Inserts stuff in container at position pos.

void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff);
Erases elements from array with indices ranging from from (inclusive) to to (exclusive).

Erases element from array at index from.

Replaces elements from array with indices ranging from from (inclusive) to to (exclusive) with the range stuff. Expands or shrinks the array as needed.

struct Appender(A : T[],T);
Implements an output range that appends data to an array. This is recommended over a ~= data when appending many elements because it is more efficient.

Example:
auto app = appender!string();
string b = "abcdefg";
foreach (char c; b) app.put(c);
assert(app.data == "abcdefg");

int[] a = [ 1, 2 ];
auto app2 = appender(a);
app2.put(3);
app2.put([ 4, 5, 6 ]);
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);

__ctor;
Construct an appender with a given array. Note that this does not copy the data. If the array has a larger capacity as determined by arr.capacity, it will be used by the appender. After initializing an appender on an array, appending to the original array will reallocate.

void reserve(size_t newCapacity);
Reserve at least newCapacity elements for appending. Note that more elements may be reserved than requested. If newCapacity < capacity, then nothing is done.

size_t capacity();
Returns the capacity of the array (the maximum number of elements the managed array can accommodate before triggering a reallocation). If any appending will reallocate, capacity returns 0.

T[] data();
Returns the managed array.

template put(U) if (isImplicitlyConvertible!(U,T) || isSomeChar!(T) && isSomeChar!(U))
Appends one item to the managed array.

void put(U item);
Appends one item to the managed array.

template put(Range) if (isInputRange!(Range) && is(typeof(Appender.init.put(items.front))))
Appends an entire range to the managed array.

void put(Range items);
Appends an entire range to the managed array.

void clear();
Clears the managed array.

void shrinkTo(size_t newlength);
Shrinks the managed array to the given length. Passing in a length that's greater than the current array length throws an enforce exception.

struct RefAppender(A : T[],T);
An appender that can update an array in-place. It forwards all calls to an underlying appender implementation. Any calls made to the appender also update the pointer to the original array passed in.

__ctor;
Construct a ref appender with a given array reference. This does not copy the data. If the array has a larger capacity as determined by arr.capacity, it will be used by the appender. RefAppender assumes that arr is a non-null value.

Note, do not use builtin appending (i.e. ~=) on the original array passed in until you are done with the appender, because calls to the appender override those appends.

size_t capacity();
Returns the capacity of the array (the maximum number of elements the managed array can accommodate before triggering a reallocation). If any appending will reallocate, capacity returns 0.

T[] data();
Returns the managed array.

Appender!(E[]) appender(A : E[], E)(A array = null);
Convenience function that returns an Appender!(A) object initialized with array.

RefAppender!(E[]) appender(A : E[]*, E)(A array);
Convenience function that returns a RefAppender!(A) object initialized with array. Don't use null for the array pointer, use the other version of appender instead.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


std.base64

Encoding / Decoding Base64 format.

Implemented according to RFC 4648 - The Base16.

Example:
 ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e];
 Base64.encode(data);        //-> "FPucA9l+"
 Base64.decode("FPucA9l+");  //-> [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]
Support Range interface using Encoder / Decoder.

Example:
 // Create MIME Base64 with CRLF, per line 76.
 foreach (encoded; Base64.encoder(f.byChunk(57))) {
     mime64.put(encoded);
     mime64.put("\r\n");
 }

License:
Boost License 1.0.

Authors:
Masahiro Nakagawa, Daniel Murphy (Single value Encoder and Decoder)

alias Base64;
The Base64

alias Base64URL;
The "URL and Filename safe" Base64

template Base64Impl(char Map62th,char Map63th,char Padding = '=')
Core implementation for Base64 format.

Example:
 alias Base64Impl!('+', '/')                   Base64;    // The Base64 format(Already defined).
 alias Base64Impl!('!', '=', Base64.NoPadding) Base64Re;  // non-standard Base64 format for Regular expression

NOTE:
encoded-string doesn't have padding character if set Padding parameter to NoPadding.

size_t encodeLength(in size_t sourceLength);
Calculates the minimum length for encoding.

Parameters:
size_t sourceLength the length of source array.

Returns:
the calculated length using sourceLength.

template encode(R1,R2) if (isArray!(R1) && is(ElementType!(R1) : ubyte) && is(R2 == char[]))
template encode(R1,R2) if (!isArray!(R1) && isInputRange!(R1) && is(ElementType!(R1) : ubyte) && hasLength!(R1) && is(R2 == char[]))
Encodes source into buffer.

Parameters:
source | an InputRange to encode.
range | a buffer to store encoded result.

Returns:
the encoded string that slices buffer.

template encode(R1,R2) if (isArray!(R1) && is(ElementType!(R1) : ubyte) && !is(R2 == char[]))
template encode(R1,R2) if (!isArray!(R1) && isInputRange!(R1) && is(ElementType!(R1) : ubyte) && hasLength!(R1) && !is(R2 == char[]) && isOutputRange!(R2,char))
Encodes source into range.

Parameters:
source | an InputRange to encode.
range | an OutputRange to put encoded result.

Returns:
the number of calling put.

size_t encode(in R1 source, R2 range);
Encodes source into range.

Parameters:
R1 source | an InputRange to encode.
R2 range | an OutputRange to put encoded result.

Returns:
the number of calling put.

template encode(Range) if (isArray!(Range) && is(ElementType!(Range) : ubyte))
template encode(Range) if (!isArray!(Range) && isInputRange!(Range) && is(ElementType!(Range) : ubyte) && hasLength!(Range))
Encodes source to new buffer.

Shortcut to encode(source, buffer) function.

template Encoder(Range) if (isInputRange!(Range) && (is(ElementType!(Range) : const(ubyte)[]) || is(ElementType!(Range) : const(char)[])))
Range that encodes chunk data at a time.

template Encoder(Range) if (isInputRange!(Range) && is(ElementType!(Range) : ubyte))
Range that encodes single character at a time.

template encoder(Range) if (isInputRange!(Range))
Iterates through an InputRange at a time by using Encoder.

Default Encoder encodes chunk data.

Example:
 foreach (encoded; Base64.encoder(f.byLine())) {
     ... use encoded line ...
 }
In addition, You can use Encoder that returns encoded single character. This Encoder performs Range-based and lazy encoding.

Example:
 // The ElementType of data is not aggregation type
 foreach (encoded; Base64.encoder(data)) {
     ... use encoded character ...
 }

Parameters:
range an InputRange to iterate.

Returns:
a Encoder object instantiated and initialized according to the arguments.

Encoder!(Range) encoder(Range range);
Iterates through an InputRange at a time by using Encoder.

Default Encoder encodes chunk data.

Example:
 foreach (encoded; Base64.encoder(f.byLine())) {
     ... use encoded line ...
 }
In addition, You can use Encoder that returns encoded single character. This Encoder performs Range-based and lazy encoding.

Example:
 // The ElementType of data is not aggregation type
 foreach (encoded; Base64.encoder(data)) {
     ... use encoded character ...
 }

Parameters:
Range range an InputRange to iterate.

Returns:
a Encoder object instantiated and initialized according to the arguments.

size_t decodeLength(in size_t sourceLength);
Calculates the minimum length for decoding.

Parameters:
size_t sourceLength the length of source array.

Returns:
calculated length using sourceLength.

template decode(R1,R2) if (isArray!(R1) && is(ElementType!(R1) : dchar) && is(R2 == ubyte[]) && isOutputRange!(R2,ubyte))
template decode(R1,R2) if (!isArray!(R1) && isInputRange!(R1) && is(ElementType!(R1) : dchar) && hasLength!(R1) && is(R2 == ubyte[]) && isOutputRange!(R2,ubyte))
Decodes source into buffer.

Parameters:
source | an InputRange to decode.
buffer | a buffer to store decoded result.

Returns:
the decoded string that slices buffer.

Throws:
an Exception if source has character outside base-alphabet.

template decode(R1,R2) if (isArray!(R1) && is(ElementType!(R1) : dchar) && !is(R2 == ubyte[]) && isOutputRange!(R2,ubyte))
template decode(R1,R2) if (!isArray!(R1) && isInputRange!(R1) && is(ElementType!(R1) : dchar) && hasLength!(R1) && !is(R2 == ubyte[]) && isOutputRange!(R2,ubyte))
Decodes source into range.

Parameters:
source | an InputRange to decode.
range | an OutputRange to put decoded result

Returns:
the number of calling put.

Throws:
an Exception if source has character outside base-alphabet.

size_t decode(in R1 source, R2 range);
Decodes source into range.

Parameters:
R1 source | an InputRange to decode.
R2 range | an OutputRange to put decoded result

Returns:
the number of calling put.

Throws:
an Exception if source has character outside base-alphabet.

template decode(Range) if (isArray!(Range) && is(ElementType!(Range) : dchar))
template decode(Range) if (!isArray!(Range) && isInputRange!(Range) && is(ElementType!(Range) : dchar) && hasLength!(Range))
Decodes source into new buffer.

Shortcut to decode(source, buffer) function.

template Decoder(Range) if (isInputRange!(Range) && (is(ElementType!(Range) : const(char)[]) || is(ElementType!(Range) : const(ubyte)[])))
Range that decodes chunk data at a time.

template Decoder(Range) if (isInputRange!(Range) && is(ElementType!(Range) : char))
Range that decodes single character at a time.

template decoder(Range) if (isInputRange!(Range))
Iterates through an InputRange at a time by using Decoder.

Default Decoder decodes chunk data.

Example:
 foreach (decoded; Base64.decoder(f.byLine())) {
     ... use decoded line ...
 }
In addition, You can use Decoder that returns decoded single character. This Decoder performs Range-based and lazy decoding.

Example:
 auto encoded = Base64.encoder(cast(ubyte[])"0123456789");
 foreach (n; map!q{a - '0'}(Base64.decoder(encoded))) {
     ... do something with n ...
 }

NOTE:
If you use ByChunk, chunk-size should be the multiple of 4. Decoder can't judge a encode-boundary.

Parameters:
range an InputRange to iterate.

Returns:
a Decoder object instantiated and initialized according to the arguments.

Decoder!(Range) decoder(Range range);
Iterates through an InputRange at a time by using Decoder.

Default Decoder decodes chunk data.

Example:
 foreach (decoded; Base64.decoder(f.byLine())) {
     ... use decoded line ...
 }
In addition, You can use Decoder that returns decoded single character. This Decoder performs Range-based and lazy decoding.

Example:
 auto encoded = Base64.encoder(cast(ubyte[])"0123456789");
 foreach (n; map!q{a - '0'}(Base64.decoder(encoded))) {
     ... do something with n ...
 }

NOTE:
If you use ByChunk, chunk-size should be the multiple of 4. Decoder can't judge a encode-boundary.

Parameters:
Range range an InputRange to iterate.

Returns:
a Decoder object instantiated and initialized according to the arguments.

Masahiro Nakagawa 2010-. | Page generated by Ddoc.


std.bigint

Arbitrary-precision ('bignum') arithmetic

Performance is optimized for numbers below ~1000 decimal digits. For X86 machines, highly optimised assembly routines are used.

The following algorithms are currently implemented:
  • Karatsuba multiplication
  • Squaring is optimized independently of multiplication
  • Divide-and-conquer division
  • Binary exponentiation

For very large numbers, consider using the GMP library instead.

License:
Boost License 1.0.

Authors:
Don Clugston

struct BigInt;
A struct representing an arbitrary precision integer

All arithmetic operations are supported, except unsigned shift right (>>>). Logical operations are not currently supported.

BigInt implements value semantics using copy-on-write. This means that assignment is cheap, but operations such as x++ will cause heap allocation. (But note that for most bigint operations, heap allocation is inevitable anyway).

Example:
        BigInt a = "9588669891916142";
        BigInt b = "7452469135154800";
        auto c = a * b;
        assert(c == "71459266416693160362545788781600");
        auto d = b * a;
        assert(d == "71459266416693160362545788781600");
        assert(d == c);
        d = c * "794628672112";
        assert(d == "56783581982794522489042432639320434378739200");
        auto e = c + d;
        assert(e == "56783581982865981755459125799682980167520800");
        auto f = d + c;
        assert(f == e);
        auto g = f - c;
        assert(g == d);
        g = f - d;
        assert(g == c);
        e = 12345678;
        g = c + e;
        auto h = g / b;
        auto i = g % b;
        assert(h == a);
        assert(i == e);
        BigInt j = "-0x9A56_57f4_7B83_AB78";
        j ^^= 11;

__ctor(T : string)();
Construct a BigInt from a decimal or hexadecimal string. The number must be in the form of a D decimal or hex literal: It may have a leading + or - sign; followed by "0x" if hexadecimal. Underscores are permitted.

BUG:
Should throw a IllegalArgumentException/ConvError if invalid character found

__ctor(T : long)();

void opAssign(T : long)(T x);

void opAssign(T : BigInt)(T x);

bool opEquals(Tdummy = void)(ref const BigInt y);

bool opEquals(T : int)(T y);

int opCmp(T : long)(T y);

int opCmp(T : BigInt)(T y);

const pure long toLong();
Returns the value of this BigInt as a long, or +- long.max if outside the representable range.

const pure long toInt();
Returns the value of this BigInt as an int, or +- int.max if outside the representable range.

const pure size_t uintLength();
Number of significant uints which are used in storing this number. The absolute value of this BigInt is always < 2^^(32*uintLength)

const pure size_t ulongLength();
Number of significant ulongs which are used in storing this number. The absolute value of this BigInt is always < 2^^(64*ulongLength)

const void toString(void delegate(const(char)[]) sink, string formatString);
Convert the BigInt to string, passing it to 'sink'.

The output format is controlled via formatString:
"d" | Decimal
"x" | Hexadecimal, lower case
"X" | Hexadecimal, upper case
"s" | Default formatting (same as "d")
null | Default formatting (same as "d")

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.bind

Bind function arguments to functions.

References:
boost:: bind

License:
Boost License 1.0.

Authors:
Tomasz Stachowiak

const DynArg!(0) _0;
const DynArg!(1) _1;
const DynArg!(2) _2;
const DynArg!(3) _3;
const DynArg!(4) _4;
const DynArg!(5) _5;
const DynArg!(6) _6;
const DynArg!(7) _7;
const DynArg!(8) _8;
const 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

template append(X)
Yields a tuple with an extra element added at its end

appendT!(X) append(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

template prepend(X)
Yields a tuple with an extra element added at its beginning

prependT!(X) prepend(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/ref parameters, by converting them to pointers internally. A function like:
void foo(ref 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.

Copyright Tomasz Stachowiak 2006 - 2009. | Page generated by Ddoc.


std.bitmanip

Bit-level manipulation facilities.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

template bitfields(T...)
Allows creating bit fields inside structs and classes.

Example:
struct A
{
    int a;
    mixin(bitfields!(
        uint, "x",    2,
        int,  "y",    3,
        uint, "z",    2,
        bool, "flag", 1));
}
A obj;
obj.x = 2;
obj.z = obj.x;
The example above creates a bitfield pack of eight bits, which fit in one ubyte. The bitfields are allocated starting from the least significant bit, i.e. x occupies the two least significant bits of the bitfields storage.

The sum of all bit lengths in one bitfield instantiation must be exactly 8, 16, 32, or 64. If padding is needed, just allocate one bitfield with an empty name.

Example:
struct A
{
    mixin(bitfields!(
        bool, "flag1",    1,
        bool, "flag2",    1,
        uint, "",         6));
}
The type of a bit field can be any integral type or enumerated type. The most efficient type to store in bitfields is bool, followed by unsigned types, followed by signed types.

struct FloatRep;
Allows manipulating the fraction, exponent, and sign parts of a float separately. The definition is:

struct FloatRep
{
    union
    {
        float value;
        mixin(bitfields!(
                  uint,  "fraction", 23,
                  ubyte, "exponent",  8,
                  bool,  "sign",      1));
    }
    enum uint bias = 127, fractionBits = 23, exponentBits = 8, signBits = 1;
}

struct DoubleRep;
Allows manipulating the fraction, exponent, and sign parts of a double separately. The definition is:

struct DoubleRep
{
    union
    {
        double value;
        mixin(bitfields!(
                  ulong,   "fraction", 52,
                  ushort,  "exponent", 11,
                  bool,    "sign",      1));
    }
    enum uint bias = 1023, signBits = 1, fractionBits = 52, exponentBits = 11;
}

struct BitArray;
An array of bits.

const 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(scope int delegate(ref bool) dg);
int opApply(scope 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.

const bool opEquals(ref const 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 Digital Mars 2007 - 2009. | 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.

WARNING:
This module is being phased out. You may want to use std.variant for new code.

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.

BUGS:
  • Bugzilla 309
  • Bugzilla 1968

License:
Boost License 1.0.

Authors:
Burton Radons

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.

const bool unboxable(TypeInfo test);
Return whether this value could be unboxed as the given type without throwing.

const 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.

const const(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.

string 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 "".

const bool opEquals(ref const 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 Burton Radons 2007 - 2009. | Page generated by Ddoc.


std.compiler

Identify the compiler used and its various features.

License:
Boost License 1.0.

Authors:
Walter Bright

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 Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.complex

Module that will replace the built-in types cfloat, cdouble, creal, ifloat, idouble, and ireal.

Authors:
Lars Tandle Kyllingstad

License:
Boost License 1.0

struct Complex(T) if (isFloatingPoint!(T));
A complex number parametrised by a type T.

BUGS:
Some operators, such as opAssign and opOpAssign, should return by ref, but currently don't. This will be implemented as soon as DMD bug 2460 is fixed.

T re;
The real part of the number.

T im;
The imaginary part of the number.

const T abs();
Calculate the absolute value (or modulus) of the number.

const T arg();
Calculate the argument (or phase) of the number.

const Complex conj();
Return the complex conjugate of the number.

const string toString(void delegate(const(char)[]) sink = null, string formatSpec = "%s");
Convert the complex number to a string representation.

If a sink delegate is specified, the string is passed to it and this function returns null. Otherwise, this function returns the string representation directly.

The output format is controlled via formatSpec, which should consist of a single POSIX format specifier, including the percent (%) character. Note that complex numbers are floating point numbers, so the only valid format characters are 'e', 'f', 'g', 'a', and 's', where 's' gives the default behaviour. Positional parameters are not valid in this context.

See the std.format documentation for more information.

Complex!(CommonType!(T,U)) fromPolar(T, U)(T modulus, U argument);
Construct a complex number given its absolute value and argument.

Copyright (c) 2010, Lars T. Kyllingstad. | Page generated by Ddoc.


std.concurrency

This is a low-level messaging API upon which more structured or restrictive APIs may be built. The general idea is that every messageable entity is represented by a common handle type (called a Cid in this implementation), which allows messages to be sent to in-process threads, on-host processes, and foreign-host processes using the same interface. This is an important aspect of scalability because it allows the components of a program to be spread across available resources with few to no changes to the actual implementation.

Right now, only in-process threads are supported and referenced by a more specialized handle called a Tid. It is effectively a subclass of Cid, with additional features specific to in-process messaging.

License:
Boost License 1.0.

Authors:
Sean Kelly

class MessageMismatch: object.Exception;

class OwnerTerminated: object.Exception;

class LinkTerminated: object.Exception;

class PriorityMessageException: object.Exception;

class MailboxFull: object.Exception;

struct Tid;
An opaque type used to represent a logical local process.

Tid thisTid();
Returns the caller's Tid.

Tid spawn(T...)(void function(T) fn, T args);
Executes the supplied function in a new context represented by Tid. The calling context is designated as the owner of the new context. When the owner context terminated an OwnerTerminated message will be sent to the new context, causing an OwnerTerminated exception to be thrown on receive().

Parameters:
fn | The function to execute.
args | Arguments to the function.

Returns:
A Tid representing the new context.

Tid spawnLinked(T...)(void function(T) fn, T args);
Executes the supplied function in a new context represented by Tid. This new context is linked to the calling context so that if either it or the calling context terminates a LinkTerminated message will be sent to the other, causing a LinkTerminated exception to be thrown on receive(). The owner relationship from spawn() is preserved as well, so if the link between threads is broken, owner termination will still result in an OwnerTerminated exception to be thrown on receive().

Parameters:
fn | The function to execute.
args | Arguments to the function.

Returns:
A Tid representing the new context.

void send(T...)(Tid tid, T vals);
Sends the supplied value to the context represented by tid.

void prioritySend(T...)(Tid tid, T vals);

void receive(T...)(T ops);

receiveOnlyRet!(T) receiveOnly(T...)();

bool receiveTimeout(T...)(long ms, T ops);

enum OnCrowding;
These behaviors may be specified when a mailbox is full.

block
Wait until room is available.

throwException
Throw a MailboxFull exception.

ignore
Abort the send and return.

void setMaxMailboxSize(Tid tid, size_t messages, OnCrowding doThis);
Sets a limit on the maximum number of user messages allowed in the mailbox. If this limit is reached, the caller attempting to add a new message will execute the behavior specified by doThis. If messages is zero, the mailbox is unbounded.

Parameters:
Tid tid | The Tid of the thread for which this limit should be set.
size_t messages | The maximum number of messages or zero if no limit.
OnCrowding doThis | The behavior executed when a message is sent to a full mailbox.

void setMaxMailboxSize(Tid tid, size_t messages, bool function(Tid) onCrowdingDoThis);
Sets a limit on the maximum number of user messages allowed in the mailbox. If this limit is reached, the caller attempting to add a new message will execute onCrowdingDoThis. If messages is zero, the mailbox is unbounded.

Parameters:
Tid tid | The Tid of the thread for which this limit should be set.
size_t messages | The maximum number of messages or zero if no limit.
bool function(Tid) onCrowdingDoThis | The routine called when a message is sent to a full mailbox.

struct List(T);

Copyright Sean Kelly 2009 - 2010. | Page generated by Ddoc.


std.container

Defines generic containers.

License:
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at boost.org/LICENSE_1_0.txt).

Authors:
Steven Schveighoffer, Andrei Alexandrescu

Container primitives. Below, C means a container type, c is a value of container type, l represents the effective length of value x, which could be a single element (in which case l is 1), a container, or a range.
Syntax | Ο(·) | Description
Creates a container of type C from either another container or a range.
Returns a duplicate of the container.
Returns the concatenation of c and r. x may be a single element or an input range.
Returns the concatenation of x and c. x may be a single element or an input range type.
Iteration
c.Range |  | The primary range type associated with the container.
c[] | Returns a range iterating over the entire container, in a container-defined order.
Fetches a portion of the container from key a to key b.
Capacity
c.empty | 1 | Returns true if the container has no elements, false otherwise.
c.length | Returns the number of elements in the container.
Forces the number of elements in the container to n. If the container ends up growing, the added elements are initialized in a container-dependent manner (usually with T.init).
c.capacity | Returns the maximum number of elements that can be stored in the container without triggering a reallocation.
c.reserve(x) | l | Forces capacity to at least x without reducing it.
Access
Returns the first element of the container, in a container-defined order.
Destructively reads and returns the first element of the container. The slot is not removed from the container; it is left initalized with T.init. This routine need not be defined if front returns a ref.
Assigns v to the first element of the container.
Returns the last element of the container, in a container-defined order.
Destructively reads and returns the first element of the container. The slot is not removed from the container; it is left initalized with T.init. This routine need not be defined if front returns a ref.
Assigns v to the last element of the container.
Provides indexed access into the container. The index type is container-defined. A container may define several index types (and consequently overloaded indexing).
Destructively reads and returns the value at position x. The slot is not removed from the container; it is left initialized with T.init.
Sets element at specified index into the container.
Performs read-modify-write operation at specified index into the container.
Operations
Returns nonzero if e is found in c.
Returns a range of all elements strictly less than v.
Returns a range of all elements strictly greater than v.
Returns a range of all elements in c that are equal to v.
Modifiers
Appends x to c. x may be a single element or an input range type.
Removes all elements in c.
Inserts x in c at a position (or positions) chosen by c.
Same as c.insert(x), but is guaranteed to not invalidate any ranges.
Same as c.insert(v) but relaxes complexity to linear.
Same as c.stableInsert(v) but relaxes complexity to linear.
Removes some element from c and returns it.
Same as c.removeAny(v), but is guaranteed to not invalidate any iterators.
Inserts v at the front of c.
Same as c.insertFront(v), but guarantees no ranges will be invalidated.
Inserts v at the back of c.
Same as c.insertBack(v), but guarantees no ranges will be invalidated.
Removes the element at the front of c.
Same as c.removeFront(), but guarantees no ranges will be invalidated.
Removes the value at the back of c.
Same as c.removeBack(), but guarantees no ranges will be invalidated.
Removes range r from c.
Same as c.remove(r), but guarantees iterators are not invalidated.
Removes range r from c.
Same as c.linearRemove(r), but guarantees iterators are not invalidated.
Removes an element from c by using its key k. The key's type is defined by the container.

Container make(Container, T...)(T arguments);
Container make(Container, T...)(T arguments);
Returns an initialized container. This function is mainly for eliminating construction differences between class containers and struct containers.

struct SList(T);
Implements a simple and fast singly-linked list.

template __ctor(U) if (isImplicitlyConvertible!(U,T))
Constructor taking a number of nodes

template __ctor(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),T) && !is(Stuff == T[]))
Constructor taking an input range

const bool opEquals(ref const SList rhs);
Comparison for equality.

Complexity:
Ο(min(n, n1)) where n1 is the number of elements in rhs.

struct Range;
Defines the container's primary range, which embodies a forward range.

const bool empty();
Range save();
T front();
void front(T value);
void popFront();
Forward range primitives.

const bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

SList dup();
Duplicates the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

Range opSlice();
Returns a range that iterates over all elements of the container, in forward order.

Complexity:
Ο(1)

T front();
Forward to opSlice().front.

Complexity:
Ο(1)

void front(T value);
Forward to opSlice().front(value).

Complexity:
Ο(1)

template opBinary(string op,Stuff) if (op == "~" && is(typeof(SList(rhs))))
Returns a new SList that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

SList opBinary(Stuff rhs);
Returns a new SList that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

void clear();
Removes all contents from the SList.

Postcondition:
empty

Complexity:
Ο(1)

template insertFront(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),T))
template insertFront(Stuff) if (isImplicitlyConvertible!(Stuff,T))
alias insert;
alias stableInsert;
alias stableInsertFront;
Inserts stuff to the front of the container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(log(n))

size_t insertFront(Stuff stuff);
Inserts stuff to the front of the container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(log(n))

T removeAny();
alias stableRemoveAny;
Picks one value from the front of the container, removes it from the container, and returns it.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(1).

void removeFront();
alias stableRemoveFront;
Removes the value at the front of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Precondition:
!empty

Complexity:
Ο(1).

size_t removeFront(size_t howMany);
alias stableRemoveFront;
Removes howMany values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove howMany elements. Instead, if howMany > n, all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements removed

Complexity:
Ο(howMany * log(n)).

template insertAfter(Stuff)
Inserts stuff after range r, which must be a range previously extracted from this container. Given that all ranges for a list end at the end of the list, this function essentially appends to the list and uses r as a potentially fast way to reach the last node in the list. (Ideally r is positioned near or at the last element of the list.)

stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

size_t insertAfter(Range r, Stuff stuff);
Inserts stuff after range r, which must be a range previously extracted from this container. Given that all ranges for a list end at the end of the list, this function essentially appends to the list and uses r as a potentially fast way to reach the last node in the list. (Ideally r is positioned near or at the last element of the list.)

stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

template insertAfter(Stuff)
alias stableInsertAfter;
Similar to insertAfter above, but accepts a range bounded in count. This is important for ensuring fast insertions in the middle of the list. For fast insertions after a specified position r, use insertAfter(take(r, 1), stuff). The complexity of that operation only depends on the number of elements in stuff.

Precondition:
r.original.empty || r.maxLength > 0

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

size_t insertAfter(Take!(Range) r, Stuff stuff);
Similar to insertAfter above, but accepts a range bounded in count. This is important for ensuring fast insertions in the middle of the list. For fast insertions after a specified position r, use insertAfter(take(r, 1), stuff). The complexity of that operation only depends on the number of elements in stuff.

Precondition:
r.original.empty || r.maxLength > 0

Returns:
The number of values inserted.

Complexity:
Ο(k + m), where k is the number of elements in r and m is the length of stuff.

Range linearRemove(Range r);
Removes a range from the list in linear time.

Returns:
An empty range.

Complexity:
Ο(n)

Range linearRemove(Take!(Range) r);
alias stableLinearRemove;
Removes a Take!Range from the list in linear time.

Returns:
A range comprehending the elements after the removed range.

Complexity:
Ο(n)

struct Array(T) if (!is(T : const(bool)));
Array type with deterministic control of memory. The memory allocated for the array is reclaimed as soon as possible; there is no reliance on the garbage collector. Array uses malloc and free for managing its own memory.

const bool opEquals(ref const Array rhs);
Comparison for equality.

struct Range;
Defines the container's primary range, which is a random-access range.

const bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

Array dup();
Duplicates the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

const size_t length();
Returns the number of elements in the container.

Complexity:
Ο(1).

size_t capacity();
Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion.

Complexity:
Ο(1)

void reserve(size_t elements);
Ensures sufficient capacity to accommodate e elements.

Postcondition:
capacity >= e

Complexity:
Ο(1)

Range opSlice();
Returns a range that iterates over elements of the container, in forward order.

Complexity:
Ο(1)

Range opSlice(size_t a, size_t b);
Returns a range that iterates over elements of the container from index a up to (excluding) index b.

Precondition:
a <= b && b <= length

Complexity:
Ο(1)

const size_t opDollar();
@@@BUG@@@ This doesn't work yet

T front();
void front(T value);
T back();
void back(T value);
Forward to opSlice().front and opSlice().back, respectively.

Precondition:
!empty

Complexity:
Ο(1)

T opIndex(size_t i);
void opIndexAssign(T value, size_t i);
template opIndexOpAssign(string op)
Indexing operators yield or modify the value at a specified index.

Precondition:
i < length

Complexity:
Ο(1)

template opBinary(string op,Stuff) if (op == "~")
Returns a new container that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

Complexity:
Ο(n + m), where m is the number of elements in stuff

Array opBinary(Stuff stuff);
Returns a new container that's the concatenation of this and its argument. opBinaryRight is only defined if Stuff does not define opBinary.

Complexity:
Ο(n + m), where m is the number of elements in stuff

template opOpAssign(string op,Stuff) if (op == "~")
Forwards to insertBack(stuff).

void opOpAssign(Stuff stuff);
Forwards to insertBack(stuff).

void clear();
Removes all contents from the container. The container decides how capacity is affected.

Postcondition:
empty

Complexity:
Ο(n)

void length(size_t newLength);
Sets the number of elements in the container to newSize. If newSize is greater than length, the added elements are added to unspecified positions in the container and initialized with T.init.

Complexity:
Ο(abs(n - newLength))

Postcondition:
length == newLength

T removeAny();
alias stableRemoveAny;
Picks one value in an unspecified position in the container, removes it from the container, and returns it. Implementations should pick the value that's the most advantageous for the container, but document the exact behavior. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(log(n)).

template insertBack(Stuff) if (isImplicitlyConvertible!(Stuff,T) || isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),T))
alias insert;
Inserts value to the front or back of the container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(m * log(n)), where m is the number of elements in stuff

size_t insertBack(Stuff stuff);
Inserts value to the front or back of the container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(m * log(n)), where m is the number of elements in stuff

void removeBack();
alias stableRemoveBack;
Removes the value at the back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Precondition:
!empty

Complexity:
Ο(log(n)).

size_t removeBack(size_t howMany);
alias stableRemoveBack;
Removes howMany values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove howMany elements. Instead, if howMany > n, all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements removed

Complexity:
Ο(howMany).

template insertBefore(Stuff) if (isImplicitlyConvertible!(Stuff,T))
template insertBefore(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),T))
template insertAfter(Stuff)
template replace(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),T))
template replace(Stuff) if (isImplicitlyConvertible!(Stuff,T))
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(n + m), where m is the length of stuff

size_t insertBefore(Range r, Stuff stuff);
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to T or a range of objects convertible to T. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(n + m), where m is the length of stuff

Range linearRemove(Range r);
alias stableLinearRemove;
Removes all elements belonging to r, which must be a range obtained originally from this container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
A range spanning the remaining elements in the container that initially were right after r.

Complexity:
Ο(n - m), where m is the number of elements in r

struct BinaryHeap(Store,alias less = "a < b") if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[])));
Implements a binary heap container on top of a given random-access range type (usually T[]) or a random-access container type (usually Array!T). The documentation of BinaryHeap will refer to the underlying range or container as the store of the heap.

The binary heap induces structure over the underlying store such that accessing the largest element (by using the front property) is a Ο(1) operation and extracting it (by using the removeFront() method) is done fast in Ο(log n) time.

If less is the less-than operator, which is the default option, then BinaryHeap defines a so-called max-heap that optimizes extraction of the largest elements. To define a min-heap, instantiate BinaryHeap with "a > b" as its predicate.

Simply extracting elements from a BinaryHeap container is tantamount to lazily fetching elements of Store in descending order. Extracting elements from the BinaryHeap to completion leaves the underlying store sorted in ascending order but, again, yields elements in descending order.

If Store is a range, the BinaryHeap cannot grow beyond the size of that range. If Store is a container that supports insertBack, the BinaryHeap may grow by adding elements to the container.

Example:
// Example from "Introduction to Algorithms" Cormen et al, p 146
int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
auto h = heapify(a);
// largest element
assert(h.front == 16);
// a has the heap property
assert(equal(a, [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ]));

__ctor;
Converts the store s into a heap. If initialSize is specified, only the first initialSize elements in s are transformed into a heap, after which the heap can grow up to r.length (if Store is a range) or indefinitely (if Store is a container with insertBack). Performs Ο(min(r.length, initialSize)) evaluations of less.

void acquire(Store s, size_t initialSize = size_t.max);
Takes ownership of a store. After this, manipulating s may make the heap work incorrectly.

void assume(Store s, size_t initialSize = size_t.max);
Takes ownership of a store assuming it already was organized as a heap.

bool empty();
Returns true if the heap is empty, false otherwise.

BinaryHeap dup();
Returns a duplicate of the heap. The underlying store must also support a dup method.

size_t length();
Returns the length of the heap.

size_t capacity();
Returns the capacity of the heap, which is the length of the underlying store (if the store is a range) or the capacity of the underlying store (if the store is a container).

ElementType!(Store) front();
Returns a copy of the front of the heap, which is the largest element according to less.

void clear();
Clears the heap by detaching it from the underlying store.

size_t insert(ElementType!(Store) value);
Inserts value into the store. If the underlying store is a range and length == capacity, throws an exception.

void removeFront();
Removes the largest element from the heap.

ElementType!(Store) removeAny();
Removes the largest element from the heap and returns a copy of it. The element still resides in the heap's store. For performance reasons you may want to use removeFront with heaps of objects that are expensive to copy.

void replaceFront(ElementType!(Store) value);
Replaces the largest element in the store with value.

bool conditionalInsert(ElementType!(Store) value);
If the heap has room to grow, inserts value into the store and returns true. Otherwise, if less(value, front), calls replaceFront(value) and returns again true. Otherwise, leaves the heap unaffected and returns false. This method is useful in scenarios where the smallest k elements of a set of candidates must be collected.

BinaryHeap!(Store) heapify(Store)(Store s, size_t initialSize = size_t.max);
Convenience function that returns a BinaryHeap!Store object initialized with s and initialSize.

struct Array(T) if (is(T == bool));
Array specialized for bool. Packs together values efficiently by allocating one bit per element.

struct Range;
Defines the container's primary range.

Range save();
bool empty();
T front();
void front(bool value);
T moveFront();
void popFront();
T back();
T moveBack();
void popBack();
T opIndex(size_t i);
void opIndexAssign(T value, size_t i);
T moveAt(size_t i);
const ulong length();
Range primitives

bool empty();
Property returning true if and only if the container has no elements.

Complexity:
Ο(1)

Array!(bool) dup();
Returns a duplicate of the container. The elements themselves are not transitively duplicated.

Complexity:
Ο(n).

ulong length();
Returns the number of elements in the container.

Complexity:
Ο(log(n)).

ulong capacity();
Returns the maximum number of elements the container can store without (a) allocating memory, (b) invalidating iterators upon insertion.

Complexity:
Ο(log(n)).

void reserve(ulong e);
Ensures sufficient capacity to accommodate n elements.

Postcondition:
capacity >= n

Complexity:
Ο(log(e - capacity)) if e > capacity, otherwise Ο(1).

Range opSlice();
Returns a range that iterates over all elements of the container, in a container-defined order. The container should choose the most convenient and fast method of iteration for opSlice().

Complexity:
Ο(log(n))

Range opSlice(ulong a, ulong b);
Returns a range that iterates the container between two specified positions.

Complexity:
Ο(log(n))

bool front();
void front(bool value);
bool back();
void back(bool value);
Equivalent to opSlice().front and opSlice().back, respectively.

Complexity:
Ο(log(n))

bool opIndex(ulong i);
void opIndexAssign(bool value, ulong i);
template opIndexOpAssign(string op)
T moveAt(ulong i);
Indexing operators yield or modify the value at a specified index.

template opBinary(string op,Stuff) if (op == "~")
Returns a new container that's the concatenation of this and its argument.

Complexity:
Ο(n + m), where m is the number of elements in stuff

Array!(bool) opBinary(Stuff rhs);
Returns a new container that's the concatenation of this and its argument.

Complexity:
Ο(n + m), where m is the number of elements in stuff

template opOpAssign(string op,Stuff) if (op == "~")
Forwards to insertAfter(this[], stuff).

Array!(bool) opOpAssign(Stuff stuff);
Forwards to insertAfter(this[], stuff).

void clear();
Removes all contents from the container. The container decides how capacity is affected.

Postcondition:
empty

Complexity:
Ο(n)

void length(ulong newLength);
Sets the number of elements in the container to newSize. If newSize is greater than length, the added elements are added to the container and initialized with ElementType.init.

Complexity:
Ο(abs(n - newLength))

Postcondition:
length == newLength

alias insert;
alias stableInsert;
Inserts stuff in the container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType.

The stable version guarantees that ranges iterating over the container are never invalidated. Client code that counts on non-invalidating insertion should use stableInsert.

Returns:
The number of elements added.

Complexity:
Ο(m * log(n)), where m is the number of elements in stuff

alias linearInsert;
alias stableLinearInsert;
Same as insert(stuff) and stableInsert(stuff) respectively, but relax the complexity constraint to linear.

T removeAny();
alias stableRemoveAny;
Picks one value in the container, removes it from the container, and returns it. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Precondition:
!empty

Returns:
The element removed.

Complexity:
Ο(log(n))

template insertBack(Stuff) if (is(Stuff : bool))
template insertBack(Stuff) if (isInputRange!(Stuff) && is(ElementType!(Stuff) : bool))
alias stableInsertBack;
Inserts value to the back of the container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(log(n))

ulong insertBack(Stuff stuff);
Inserts value to the back of the container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements inserted

Complexity:
Ο(log(n))

void removeBack();
alias stableRemoveBack;
Removes the value at the front or back of the container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated. The optional parameter howMany instructs removal of that many elements. If howMany > n, all elements are removed and no exception is thrown.

Precondition:
!empty

Complexity:
Ο(log(n)).

ulong removeBack(ulong howMany);
Removes howMany values at the front or back of the container. Unlike the unparameterized versions above, these functions do not throw if they could not remove howMany elements. Instead, if howMany > n, all elements are removed. The returned value is the effective number of elements removed. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of elements removed

Complexity:
Ο(howMany * log(n)). ditto

template insertBefore(Stuff)
alias stableInsertBefore;
template insertAfter(Stuff)
alias stableInsertAfter;
template replace(Stuff) if (is(Stuff : bool))
alias stableReplace;
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(n + m), where m is the length of stuff

ulong insertBefore(Range r, Stuff stuff);
Inserts stuff before, after, or instead range r, which must be a valid range previously extracted from this container. stuff can be a value convertible to ElementType or a range of objects convertible to ElementType. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
The number of values inserted.

Complexity:
Ο(n + m), where m is the length of stuff

Range linearRemove(Range r);
alias stableLinearRemove;
Removes all elements belonging to r, which must be a range obtained originally from this container. The stable version behaves the same, but guarantees that ranges iterating over the container are never invalidated.

Returns:
A range spanning the remaining elements in the container that initially were right after r.

Complexity:
Ο(n)

struct RedBlackTree(T,alias less = "a < b",bool allowDuplicates = false) if (is(typeof(less(T.init,T.init)) == bool) || is(typeof(less) == string));
Implementation of a red-black tree container.

All inserts, removes, searches, and any function in general has complexity of Ο(lg(n)).

To use a different comparison than "a < b", pass a different operator string that can be used by std.functional.binaryFun, or pass in a function, delegate, functor, or any type where less(a, b) results in a bool value.

Note that less should produce a strict ordering. That is, for two unequal elements a and b, less(a, b) == !less(b, a). less(a, a) should always equal false.

If allowDuplicates is set to true, then inserting the same element more than once continues to add more elements. If it is false, duplicate elements are ignored on insertion. If duplicates are allowed, then new elements are inserted after all existing duplicate elements.

alias Elem;
Element type for the tree

struct Range;
The range type for RedBlackTree

const bool empty();
Returns true if the range is empty

Elem front();
Returns the first element in the range

Elem back();
Returns the last element in the range

void popFront();
pop the front element from the range

complexity:
amortized Ο(1)

void popBack();
pop the back element from the range

complexity:
amortized Ο(1)

Range save();
Trivial save implementation, needed for isForwardRange.

bool empty();
Check if any elements exist in the container. Returns true if at least one element exists.

RedBlackTree dup();
Duplicate this container. The resulting container contains a shallow copy of the elements.

Complexity:
Ο(n)

Range opSlice();
Fetch a range that spans all the elements in the container.

Complexity:
Ο(log(n))

Elem front();
The front element in the container

Complexity:
Ο(log(n))

Elem back();
The last element in the container

Complexity:
Ο(log(n))

template opBinaryRight(string op) if (op == "in")
Check to see if an element exists in the container

Complexity:
Ο(log(n))

bool opBinaryRight(Elem e);
Check to see if an element exists in the container

Complexity:
Ο(log(n))

void clear();
Clear the container of all elements

Complexity:
Ο(1)

template stableInsert(Stuff) if (isImplicitlyConvertible!(Stuff,Elem))
Insert a single element in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(log(n))

size_t stableInsert(Stuff stuff);
Insert a single element in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(log(n))

template stableInsert(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),Elem))
alias insert;
Insert a range of elements in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(m * log(n))

size_t stableInsert(Stuff stuff);
Insert a range of elements in the container. Note that this does not invalidate any ranges currently iterating the container.

Complexity:
Ο(m * log(n))

Elem removeAny();
Remove an element from the container and return its value.

Complexity:
Ο(log(n))

void removeFront();
Remove the front element from the container.

Complexity:
Ο(log(n))

void removeBack();
Remove the back element from the container.

Complexity:
Ο(log(n))

Range remove(Range r);
Remove the given range from the container. Returns a range containing all the elements that were after the given range.

Complexity:
Ο(m * log(n))

Range upperBound(Elem e);
Get a range from the container with all elements that are > e according to the less comparator

Complexity:
Ο(log(n))

Range lowerBound(Elem e);
Get a range from the container with all elements that are < e according to the less comparator

Complexity:
Ο(log(n))

Range equalRange(Elem e);
Get a range from the container with all elements that are == e according to the less comparator

Complexity:
Ο(log(n))

void printTree(Node n, int indent = 0);
Print the tree. This prints a sideways view of the tree in ASCII form, with the number of indentations representing the level of the nodes. It does not print values, only the tree structure and color of nodes.

void check();
Check the tree for validity. This is called after every add or remove. This should only be enabled to debug the implementation of the RB Tree.

template __ctor(U) if (isImplicitlyConvertible!(U,Elem))
Constructor. Pass in an array of elements, or individual elements to initialize the tree with.

template __ctor(Stuff) if (isInputRange!(Stuff) && isImplicitlyConvertible!(ElementType!(Stuff),Elem) && !is(Stuff == Elem[]))
Constructor. Pass in a range of elements to initialize the tree with.

Red-black tree code copyright (C) 2008- by Steven Schveighoffer. Other code copyright 2010- Andrei Alexandrescu. All rights reserved by the respective holders. | Page generated by Ddoc.


std.contracts

This module has been scheduled for deprecation. Use std.exception instead.

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.conv

A one-stop shop for converting values from one type to another.

Copyright:
Copyright Digital Mars 2007-.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu, Shin Fujishiro, Adam D. Ruppe

class ConvException: object.Exception;
deprecated alias ConvError;
Thrown on conversion errors.

class ConvOverflowException: std.conv.ConvException;
deprecated alias ConvOverflowError;
Thrown on conversion overflow errors.

template to(T)
Entry point that dispatches to the appropriate conversion primitive. Client code normally calls to!TargetType(value) (and not some variant of toImpl).

T toImpl(T, S)(S s);
String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable).

Example:
char[] a = "abc";
auto b = to!dstring(a);
assert(b == "abc"w);

T toImpl(T, S)(S s, in T leftBracket = "[", in T separator = ", ", in T rightBracket = "]");
Converts array (other than strings) to string. The left bracket, separator, and right bracket are configurable. Each element is converted by calling to!T.

T toImpl(T, S)(S s, in T leftBracket = "[", in T keyval = ":", in T separator = ", ", in T rightBracket = "]");
Associative array to string conversion. The left bracket, key-value separator, element separator, and right bracket are configurable. Each element is printed by calling to!T.

T toImpl(T, S)(S s, in T nullstr = "null");
Object to string conversion calls toString against the object or returns nullstr if the object is null.

T toImpl(T, S)(S s);
Struct to string conversion calls toString against the struct if it is defined.

T toImpl(T, S)(S s, in T left = S.stringof ~ "(", in T separator = ", ", in T right = ")");
For structs that do not define toString, the conversion to string produces the list of fields.

T toImpl(T, S)(S s);
Enumerated types are converted to strings as their symbolic names.

T toImpl(T, S)(S s, in T left = S.stringof ~ "(", in T right = ")");
A typedef Type Symbol is converted to string as "Type(value)".

Target toImpl(Target, Source)(Source value);
If the source type is implicitly convertible to the target type, to simply performs the implicit conversion.

T toImpl(T, S)(S b);
Boolean values are printed as "true" or "false".

T toImpl(T, S)(S value);
When the source is a wide string, it is first converted to a narrow string and then parsed.

T toImpl(T, S)(S value);
When the source is a narrow string, normal text parsing occurs.

T toImpl(T, S)(S value);
Object-to-object conversions throw exception when the source is non-null and the target is null.

T toImpl(T, S)(S value);
Object-to-non-object conversions look for a method "to" of the source object.

Example:
class Date
{
    T to(T)() if(is(T == long))
    {
        return timestamp;
    }
    ...
}

unittest
{
    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
    auto d = new Date;
    auto ts = to!long(d); // same as d.to!long()
}

T toImpl(T, S)(S value);
Narrowing numeric-numeric conversions throw when the value does not fit in the narrower type.

T toImpl(T, S)(S src);
Array-to-array conversion (except when target is a string type) converts each element in turn by using to.

T toImpl(T, S)(S src);
Associative array to associative array conversion converts each key and each value in turn.

template roundTo(Target)
Rounded conversion from floating point to integral.

Example:
  assert(roundTo!(int)(3.14) == 3);
  assert(roundTo!(int)(3.49) == 3);
  assert(roundTo!(int)(3.5) == 4);
  assert(roundTo!(int)(3.999) == 4);
  assert(roundTo!(int)(-3.14) == -3);
  assert(roundTo!(int)(-3.49) == -3);
  assert(roundTo!(int)(-3.5) == -4);
  assert(roundTo!(int)(-3.999) == -4);
Rounded conversions do not work with non-integral target types.

Target parse(Target, Source)(ref Source s);
Target parse(Target, Source)(ref Source s, uint radix);
The parse family of functions works quite like the to family, except that (1) it only works with strings as input, (2) takes the input string by reference and advances it to the position following the conversion, and (3) does not throw if it could not convert the entire string. It still throws if an overflow occurred during conversion or if no character of the input string was meaningfully converted.

Example:
string test = "123 \t  76.14";
auto a = parse!(uint)(test);
assert(a == 123);
assert(test == " \t  76.14"); // parse bumps string
munch(test, " \t\n\r"); // skip ws
assert(test == "76.14");
auto b = parse!(double)(test);
assert(b == 76.14);
assert(test == "");

Target parse(Target, Source)(ref Source s);
Parsing one character off a string returns the character and bumps the string up one position.

T toImpl(T, S)(S value);
Small unsigned integers to strings.

T toImpl(T, S)(S value);
Small signed integers to strings.

T toImpl(T, S)(S input);
Unsigned integers (uint and ulong) to string.

T toImpl(T, S)(S c);
char, wchar, dchar to a string type.

T toImpl(T, S)(S value);
Signed values (int and long).

T toImpl(T, S)(S s);
C-style strings

T toImpl(T, S)(S f);
float to all string types.

T toImpl(T, S)(S d);
double to all string types.

T toImpl(T, S)(S r);
real to all string types.

T toImpl(T, S)(S f);
ifloat to all string types.

T toImpl(T, S)(S d);
idouble to all string types.

T toImpl(T, S)(S r);
ireal to all string types.

T toImpl(T, S)(S f);
cfloat to all string types.

T toImpl(T, S)(S d);
cdouble to all string types.

T toImpl(T, S)(S r);
creal to all string types.

T toImpl(T, S)(S value, uint radix);
T toImpl(T, S)(S 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.

T toImpl(T, S)(S value);
Pointer to string conversions prints the pointer as a size_t value.

string text(T...)(T args);
wstring wtext(T...)(T args);
dstring dtext(T...)(T args);
Convenience functions for converting any number and types of arguments into text (the three character widths).

Example:
   assert(text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz");
   assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
   assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);

int octal(string num)();
long octal(string num)();
uint octal(string num)();
ulong octal(string num)();
template octal(alias s) if (isIntegral!(typeof(s)))
The octal facility is intended as an experimental facility to replace octal literals starting with '0', which many find confusing. Using octal!177 or octal!"177" instead of 0177 as an octal literal makes code clearer and the intent more visible. If use of this facility becomes preponderent, a future version of the language may deem old-style octal literals deprecated.

The rules for strings are the usual for literals: If it can fit in an int, it is an int. Otherwise, it is a long. But, if the user specifically asks for a long with the L suffix, always give the long. Give an unsigned iff it is asked for with the U or u suffix. Octals created from integers preserve the type of the passed-in integral.

Example:
// same as 0177
auto x = octal!177;
// octal is a compile-time device
enum y = octal!160;
// Create an unsigned octal
auto z = octal!"1_000_000u";

T* emplace(T, Args...)(void[] chunk, Args args);
Given a raw memory area chunk, constructs an object of non-class type T at that address. The constructor is passed the arguments Args. The chunk must be as least as large as T needs and should have an alignment multiple of T's alignment.

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object.

T* emplace(T, Args...)(T* chunk, Args args);
Similar to emplace above, except it receives a pointer to an uninitialized object of type T. This overload is useful for e.g. initializing member variables or stack variables defined with T variable = void.

Returns:
A pointer to the newly constructed object.

T emplace(T, Args...)(void[] chunk, Args args);
Given a raw memory area chunk, constructs an object of class type T at that address. The constructor is passed the arguments Args. The chunk must be as least as large as T needs and should have an alignment multiple of T's alignment. (The size of a class instance is obtained by using _traits(classInstanceSize, T)).

This function can be @trusted if the corresponding constructor of T is @safe.

Returns:
A pointer to the newly constructed object.

Copyright Digital Mars 2007-. | 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

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-2008 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());
}

BUGS:
Only works on x86 CPUs

License:
Boost License 1.0.

Authors:
Tomas Lindquist Olsen <tomas@famolsen.dk>

string toString();
Returns everything as a printable string

string vendor();
Returns vendor string

string 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

Copyright Tomas Lindquist Olsen 2007 - 2009. | Page generated by Ddoc.


std.ctype

Simple ASCII character classification functions. For Unicode classification, see std.uni.

References:
ASCII Table, Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright

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 Digital Mars 2000 - 2009. | 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)

License:
Boost License 1.0.

Authors:
Walter Bright

alias d_time;
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.

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 hourFromTime(d_time time);
Calculates the hour from time.

Parameters:
d_time time The time to compute the hour from.

Returns:
The calculated hour, 0..23.

int minFromTime(d_time time);
Calculates the minute from time.

Parameters:
d_time time The time to compute the minute from.

Returns:
The calculated minute, 0..59.

int secFromTime(d_time time);
Calculates the second from time.

Parameters:
d_time time The time to compute the second from.

Returns:
The calculated second, 0..59.

int msFromTime(d_time time);
Calculates the milisecond from time.

Parameters:
d_time time The time to compute the milisecond from.

Returns:
The calculated milisecond, 0..999.

uint daysInYear(uint year);
Calculates the number of days that exists in a year.

Leap years have 366 days, while other years have 365.

Parameters:
uint year The year to compute the number of days from.

Returns:
The number of days in the year, 365 or 366.

int dayFromYear(int year);
Calculates the number of days elapsed since 1 January 1970 until 1 January of the given year.

Parameters:
int year The year to compute the number of days from.

Returns:
The number of days elapsed.

Example:
 writeln(dayFromYear(1970)); // writes '0'
 writeln(dayFromYear(1971)); // writes '365'
 writeln(dayFromYear(1972)); // writes '730'

int yearFromTime(d_time t);
Calculates the year from the d_time t.

bool 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.

Parameters:
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.

Parameters:
int month 1..12

string UTCtoString(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.UTCtoString(lNow);

deprecated alias toString;
Alias for UTCtoString (deprecated).

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, d_time_nan 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.

ulong[] benchmark(fun...)(uint times, ulong[] result = null);
Benchmarks code for speed assessment and comparison.

Parameters:
fun | aliases of callable objects (e.g. function names). Each should take no arguments.
times | The number of times each function is to be executed.
result | The optional store for the return value. If null is passed in, new store is allocated appropriately.

Returns:
An array of n uints. Element at slot i contains the number of milliseconds spent in calling the ith function times times.

Example:
int a;
void f0() { }
void f1() { auto b = a; }
void f2() { auto b = to!(string)(a); }
auto r = benchmark!(f0, f1, f2)(10_000_000);

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.demangle

Demangle D mangled names.

License:
Boost License 1.0.

Authors:
Walter Bright, Thomas Kuehne, Frits van Bommel

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 Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.encoding

Classes and functions for handling and transcoding between various encodings.

For cases where the encoding is known at compile-time, functions are provided for arbitrary encoding and decoding of characters, arbitrary transcoding between strings of different type, as well as validation and sanitization.

Encodings currently supported are UTF-8, UTF-16, UTF-32, ASCII, ISO-8859-1 (also known as LATIN-1), and WINDOWS-1252.

  • The type AsciiChar represents an ASCII character.
  • The type AsciiString represents an ASCII string.
  • The type Latin1Char represents an ISO-8859-1 character.
  • The type Latin1String represents an ISO-8859-1 string.
  • The type Windows1252Char represents a Windows-1252 character.
  • The type Windows1252String represents a Windows-1252 string.

For cases where the encoding is not known at compile-time, but is known at run-time, we provide the abstract class EncodingScheme and its subclasses. To construct a run-time encoder/decoder, one does e.g.

    auto e = EncodingScheme.create("utf-8");
This library supplies EncodingScheme subclasses for ASCII, ISO-8859-1 (also known as LATIN-1), WINDOWS-1252, UTF-8, and (on little-endian architectures) UTF-16LE and UTF-32LE; or (on big-endian architectures) UTF-16BE and UTF-32BE.

This library provides a mechanism whereby other modules may add EncodingScheme subclasses for any other encoding.

License:
Boost License 1.0.

Authors:
Janice Caron

dchar INVALID_SEQUENCE;
Special value returned by safeDecode

typedef AsciiChar;
alias AsciiString;
Defines various character sets.

typedef Latin1Char;
Defines an Latin1-encoded character.

alias Latin1String;
Defines an Latin1-encoded string (as an array of immutable(Latin1Char)).

typedef Windows1252Char;
Defines a Windows1252-encoded character.

alias Windows1252String;
Defines an Windows1252-encoded string (as an array of immutable(Windows1252Char)).

bool isValidCodePoint(dchar c);
Returns true if c is a valid code point

Note that this includes the non-character code points U+FFFE and U+FFFF, since these are valid code points (even though they are not valid characters).

Supercedes:
This function supercedes std.utf.startsValidDchar().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
dchar c the code point to be tested

string encodingName(T)();
Returns the name of an encoding.

The type of encoding cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Examples:
 assert(encodingName!(Latin1Char) == "ISO-8859-1");

bool canEncode(E)(dchar c);
Returns true iff it is possible to represent the specifed codepoint in the encoding.

The type of encoding cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Examples:
 assert(canEncode!(Latin1Char)('A'));

bool isValidCodeUnit(E)(E c);
Returns true if the code unit is legal. For example, the byte 0x80 would not be legal in ASCII, because ASCII code units must always be in the range 0x00 to 0x7F.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code unit to be tested

bool isValid(E)(const(E)[] s);
Returns true if the string is encoded correctly

Supercedes:
This function supercedes std.utf.validate(), however note that this function returns a bool indicating whether the input was valid or not, wheras the older funtion would throw an exception.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be tested

size_t validLength(E)(const(E)[] s);
Returns the length of the longest possible substring, starting from the first code unit, which is validly encoded.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be tested

immutable(E)[] sanitize(E)(immutable(E)[] s);
Sanitizes a string by replacing malformed code unit sequences with valid code unit sequences. The result is guaranteed to be valid for this encoding.

If the input string is already valid, this function returns the original, otherwise it constructs a new string by replacing all illegal code unit sequences with the encoding's replacement character, Invalid sequences will be replaced with the Unicode replacement character (U+FFFD) if the character repertoire contains it, otherwise invalid sequences will be replaced with '?'.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be sanitized

size_t firstSequence(E)(const(E)[] s);
Returns the length of the first encoded sequence.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be sliced

size_t lastSequence(E)(const(E)[] s);
Returns the length the last encoded sequence.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be sliced

sizediff_t index(E)(const(E)[] s, int n);
Returns the array index at which the (n+1)th code point begins.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Supercedes:
This function supercedes std.utf.toUTFindex().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be counted

dchar decode(S)(ref S s);
Decodes a single code point.

This function removes one or more code units from the start of a string, and returns the decoded code point which those code units represent.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Supercedes:
This function supercedes std.utf.decode(), however, note that the function codePoints() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

dchar decodeReverse(E)(ref const(E)[] s);
Decodes a single code point from the end of a string.

This function removes one or more code units from the end of a string, and returns the decoded code point which those code units represent.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

dchar safeDecode(S)(ref S s);
Decodes a single code point. The input does not have to be valid.

This function removes one or more code units from the start of a string, and returns the decoded code point which those code units represent.

This function will accept an invalidly encoded string as input. If an invalid sequence is found at the start of the string, this function will remove it, and return the value INVALID_SEQUENCE.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string whose first code point is to be decoded

size_t encodedLength(E)(dchar c);
Returns the number of code units required to encode a single code point.

The input to this function MUST be a valid code point. This is enforced by the function's in-contract.

The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding as a template parameter.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

E[] encode(E)(dchar c);
Encodes a single code point.

This function encodes a single code point into one or more code units. It returns a string containing those code units.

The input to this function MUST be a valid code point. This is enforced by the function's in-contract.

The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding as a template parameter.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

size_t encode(E)(dchar c, E[] array);
Encodes a single code point into an array.

This function encodes a single code point into one or more code units The code units are stored in a user-supplied fixed-size array, which must be passed by reference.

The input to this function MUST be a valid code point. This is enforced by the function's in-contract.

The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding as a template parameter.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

Returns:
the number of code units written to the array

void encode(E)(dchar c, void delegate(E) dg);
Encodes a single code point to a delegate.

This function encodes a single code point into one or more code units. The code units are passed one at a time to the supplied delegate.

The input to this function MUST be a valid code point. This is enforced by the function's in-contract.

The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding as a template parameter.

Supercedes:
This function supercedes std.utf.encode(), however, note that the function codeUnits() supercedes it more conveniently.

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
c the code point to be encoded

CodePoints!(E) codePoints(E)(immutable(E)[] s);
Returns a foreachable struct which can bidirectionally iterate over all code points in a string.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

You can foreach either with or without an index. If an index is specified, it will be initialized at each iteration with the offset into the string at which the code point begins.

Supercedes:
This function supercedes std.utf.decode().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be decoded

Examples:
 string s = "hello world";
 foreach(c;codePoints(s))
 {
     // do something with c (which will always be a dchar)
 }
Note that, currently, foreach(c:codePoints(s)) is superior to foreach(c;s) in that the latter will fall over on encountering U+FFFF.

CodeUnits!(E) codeUnits(E)(dchar c);
Returns a foreachable struct which can bidirectionally iterate over all code units in a code point.

The input to this function MUST be a valid code point. This is enforced by the function's in-contract.

The type of the output cannot be deduced. Therefore, it is necessary to explicitly specify the encoding type in the template parameter.

Supercedes:
This function supercedes std.utf.encode().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
d the code point to be encoded

Examples:
 dchar d = '\u20AC';
 foreach(c;codeUnits!(char)(d))
 {
     writefln("%X",c)
 }
 // will print
 // E2
 // 82
 // AC

size_t encode(Tgt, Src, R)(in Src[] s, R range);
Encodes c in units of type E and writes the result to the output range R. Returns the number of Es written.

void transcode(Src, Dst)(immutable(Src)[] s, out immutable(Dst)[] r);
Convert a string from one encoding to another. (See also to!() below).

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Supercedes:
This function supercedes std.utf.toUTF8(), std.utf.toUTF16() and std.utf.toUTF32() (but note that to!() supercedes it more conveniently).

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s | the source string
r | the destination string

Examples:
 wstring ws;
 transcode("hello world",ws);
     // transcode from UTF-8 to UTF-16

 Latin1String ls;
 transcode(ws, ls);
     // transcode from UTF-16 to ISO-8859-1

class EncodingException: object.Exception;
The base class for exceptions thrown by this module

abstract class EncodingScheme;
Abstract base class of all encoding schemes

static void register(string className);
Registers a subclass of EncodingScheme.

This function allows user-defined subclasses of EncodingScheme to be declared in other modules.

Examples:
 class Amiga1251 : EncodingScheme
 {
     shared static this()
     {
         EncodingScheme.register("path.to.Amiga1251");
     }
 }

static EncodingScheme create(string encodingName);
Obtains a subclass of EncodingScheme which is capable of encoding and decoding the named encoding scheme.

This function is only aware of EncodingSchemes which have been registered with the register() function.

Examples:
 auto scheme = EncodingScheme.create("Amiga-1251");

abstract const string toString();
Returns the standard name of the encoding scheme

abstract const string[] names();
Returns an array of all known names for this encoding scheme

abstract const bool canEncode(dchar c);
Returns true if the character c can be represented in this encoding scheme.

abstract const size_t encodedLength(dchar c);
Returns the number of ubytes required to encode this code point.

The input to this function MUST be a valid code point.

Parameters:
dchar c the code point to be encoded

Returns:
the number of ubytes required.

abstract const size_t encode(dchar c, ubyte[] buffer);
Encodes a single code point into a user-supplied, fixed-size buffer.

This function encodes a single code point into one or more ubytes. The supplied buffer must be code unit aligned. (For example, UTF-16LE or UTF-16BE must be wchar-aligned, UTF-32LE or UTF-32BE must be dchar-aligned, etc.)

The input to this function MUST be a valid code point.

Parameters:
dchar c the code point to be encoded

Returns:
the number of ubytes written.

abstract const dchar decode(ref const(ubyte)[] s);
Decodes a single code point.

This function removes one or more ubytes from the start of an array, and returns the decoded code point which those ubytes represent.

The input to this function MUST be validly encoded.

Parameters:
const(ubyte)[] s the array whose first code point is to be decoded

abstract const dchar safeDecode(ref const(ubyte)[] s);
Decodes a single code point. The input does not have to be valid.

This function removes one or more ubytes from the start of an array, and returns the decoded code point which those ubytes represent.

This function will accept an invalidly encoded array as input. If an invalid sequence is found at the start of the string, this function will remove it, and return the value INVALID_SEQUENCE.

Parameters:
const(ubyte)[] s the array whose first code point is to be decoded

abstract const immutable(ubyte)[] replacementSequence();
Returns the sequence of ubytes to be used to represent any character which cannot be represented in the encoding scheme.

Normally this will be a representation of some substitution character, such as U+FFFD or '?'.

bool isValid(const(ubyte)[] s);
Returns true if the array is encoded correctly

Parameters:
const(ubyte)[] s the array to be tested

size_t validLength(const(ubyte)[] s);
Returns the length of the longest possible substring, starting from the first element, which is validly encoded.

Parameters:
const(ubyte)[] s the array to be tested

immutable(ubyte)[] sanitize(immutable(ubyte)[] s);
Sanitizes an array by replacing malformed ubyte sequences with valid ubyte sequences. The result is guaranteed to be valid for this encoding scheme.

If the input array is already valid, this function returns the original, otherwise it constructs a new array by replacing all illegal sequences with the encoding scheme's replacement sequence.

Parameters:
immutable(ubyte)[] s the string to be sanitized

size_t firstSequence(const(ubyte)[] s);
Returns the length of the first encoded sequence.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Parameters:
const(ubyte)[] s the array to be sliced

size_t count(const(ubyte)[] s);
Returns the total number of code points encoded in a ubyte array.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Parameters:
const(ubyte)[] s the string to be counted

sizediff_t index(const(ubyte)[] s, size_t n);
Returns the array index at which the (n+1)th code point begins.

The input to this function MUST be validly encoded. This is enforced by the function's in-contract.

Parameters:
const(ubyte)[] s the string to be counted

class EncodingSchemeASCII: std.encoding.EncodingScheme;
EncodingScheme to handle ASCII

This scheme recognises the following names: "ANSI_X3.4-1968", "ANSI_X3.4-1986", "ASCII", "IBM367", "ISO646-US", "ISO_646.irv:1991", "US-ASCII", "cp367", "csASCII" "iso-ir-6", "us"

class EncodingSchemeLatin1: std.encoding.EncodingScheme;
EncodingScheme to handle Latin-1

This scheme recognises the following names: "CP819", "IBM819", "ISO-8859-1", "ISO_8859-1", "ISO_8859-1:1987", "csISOLatin1", "iso-ir-100", "l1", "latin1"

class EncodingSchemeWindows1252: std.encoding.EncodingScheme;
EncodingScheme to handle Windows-1252

This scheme recognises the following names: "windows-1252"

class EncodingSchemeUtf8: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-8

This scheme recognises the following names: "UTF-8"

class EncodingSchemeUtf16Native: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-16 in native byte order

This scheme recognises the following names: "UTF-16LE" (little-endian architecture only) "UTF-16BE" (big-endian architecture only)

class EncodingSchemeUtf32Native: std.encoding.EncodingScheme;
EncodingScheme to handle UTF-32 in native byte order

This scheme recognises the following names: "UTF-32LE" (little-endian architecture only) "UTF-32BE" (big-endian architecture only)

Copyright Janice Caron 2008 - 2009. | Page generated by Ddoc.


std.exception

This module defines tools related to exceptions and general error handling.

Synopsis:
 string synopsis()
 {
     FILE* f = enforce(fopen("some/file"));
     // f is not null from here on
     FILE* g = enforceEx!(WriteException)(fopen("some/other/file", "w"));
     // g is not null from here on
     Exception e = collectException(write(g, readln(f)));
     if (e)
     {
         ... an exception occurred...
     }
     char[] line;
     enforce(readln(f, line));
     return assumeUnique(line);
 }

License:
Boost License 1.0

Authors:
Andrei Alexandrescu

T enforce(T, string file = __FILE__, int line = __LINE__)(T value, lazy const(char)[] msg = null);
If value is nonzero, returns it. Otherwise, throws new Exception(msg).

Example:
 auto f = enforce(fopen("data.txt"));
 auto line = readln(f);
 enforce(line.length); // expect a non-empty line

T enforce(T)(T value, lazy Throwable ex);
If value is nonzero, returns it. Otherwise, throws ex.

Example:
 auto f = enforce(fopen("data.txt"));
 auto line = readln(f);
 enforce(line.length, new IOException); // expect a non-empty line

T errnoEnforce(T, string file = __FILE__, int line = __LINE__)(T value, lazy string msg = null);
If value is nonzero, returns it. Otherwise, throws new ErrnoException(msg). The ErrnoException class assumes that the last operation has set errno to an error code.

Example:
 auto f = errnoEnforce(fopen("data.txt"));
 auto line = readln(f);
 enforce(line.length); // expect a non-empty line

template enforceEx(E)
If value is nonzero, returns it. Otherwise, throws new E(msg).

Example:
 auto f = enforceEx!(FileMissingException)(fopen("data.txt"));
 auto line = readln(f);
 enforceEx!(DataCorruptionException)(line.length);

Exception collectException(T)(lazy T expression, ref T target);
Evaluates expression. If evaluation throws an exception, return that exception. Otherwise, deposit the resulting value in target and return null.

Example:
 int[] a = new int[3];
 int b;
 assert(collectException(a[4], b));

Exception collectException(T)(lazy T expression);
Evaluates expression. If evaluation throws an exception, return that exception. Otherwise, return null. T can be void.

immutable(T)[] assumeUnique(T)(ref T[] array);
Casts a mutable array to an immutable array in an idiomatic manner. Technically, assumeUnique just inserts a cast, but its name documents assumptions on the part of the caller. assumeUnique(arr) should only be called when there are no more active mutable aliases to elements of arr. To strenghten this assumption, assumeUnique(arr) also clears arr before returning. Essentially assumeUnique(arr) indicates commitment from the caller that there is no more mutable access to any of arr's elements (transitively), and that all future accesses will be done through the immutable array returned by assumeUnique.

Typically, assumeUnique is used to return arrays from functions that have allocated and built them.

Example:
 string letters()
 {
   char[] result = new char['z' - 'a' + 1];
   foreach (i, ref e; result)
   {
     e = 'a' + i;
   }
   return assumeUnique(result);
 }
The use in the example above is correct because result was private to letters and is unaccessible in writing after the function returns. The following example shows an incorrect use of assumeUnique.

Bad:
 private char[] buffer;
 string letters(char first, char last)
 {
   if (first >= last) return null; // fine
   auto sneaky = buffer;
   sneaky.length = last - first + 1;
   foreach (i, ref e; sneaky)
   {
     e = 'a' + i;
   }
   return assumeUnique(sneaky); // BAD
 }
The example above wreaks havoc on client code because it is modifying arrays that callers considered immutable. To obtain an immutable array from the writable array buffer, replace the last line with:
 return to!(string)(sneaky); // not that sneaky anymore
The call will duplicate the array appropriately.

Checking for uniqueness during compilation is possible in certain cases (see the unique and lent keywords in the ArchJava language), but complicates the language considerably. The downside of assumeUnique's convention-based usage is that at this time there is no formal checking of the correctness of the assumption; on the upside, the idiomatic use of assumeUnique is simple and rare enough to be tolerable.

bool pointsTo(S, T)(ref const S source, ref const T target);
Returns true if source's representation embeds a pointer that points to target's representation or somewhere inside it. Note that evaluating pointsTo(x, x) checks whether x has internal pointers.

class ErrnoException: object.Exception;
Thrown if errors that set errno happen.

Copyright Andrei Alexandrescu 2008-. | Page generated by Ddoc.


std.file

Utilities for manipulating files and scanning directories. Functions in this module handle files as a unit, e.g., read or write one file at a time. For opening files and manipulating them via handles refer to module std.stdio.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

class FileException: object.Exception;
Exception thrown for file I/O errors.

immutable uint errno;
OS error code.

this(in char[] name, in char[] message);
Constructor taking the name of the file where error happened and a message describing the error.

this(in char[] name, uint errno = GetLastError);
Constructor taking the name of the file where error happened and the error number (GetLastError in Windows, getErrno in Posix).

void[] read(in char[] name, size_t upTo = (uint).max);
Read entire contents of file name and returns it as an untyped array. If the file size is larger than upTo, only upTo bytes are read.

Example:
import std.file, std.stdio;
void main()
{
   auto bytes = cast(ubyte[]) read("filename", 5);
   if (bytes.length == 5)
       writefln("The fifth byte of the file is 0x%x", bytes[4]);
}

Returns:
Untyped array of bytes read.

Throws:
FileException on error.

S readText(S = string)(in char[] name);
Read and validates (using std.utf.validate) a text file. S can be a type of array of characters of any width and constancy. No width conversion is performed; if the width of the characters in file name is different from the width of elements of S, validation will fail.

Returns:
Array of characters read.

Throws:
FileException on file error, UtfException on UTF decoding error.

Example:
enforce(system("echo abc>deleteme") == 0);
scope(exit) remove("deleteme");
enforce(chomp(readText("deleteme")) == "abc");

void write(in char[] name, const void[] buffer);
Write buffer to file name.

Throws:
FileException on error.

Example:
import std.file;
void main()
{
   int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
   write("filename", a);
   assert(cast(int[]) read("filename") == a);
}

void append(in char[] name, in void[] buffer);
Appends buffer to file name.

Throws:
FileException on error.

Example:
import std.file;
void main()
{
   int[] a = [ 0, 1, 1, 2, 3, 5, 8 ];
   write("filename", a);
   int[] b = [ 13, 21 ];
   append("filename", b);
   assert(cast(int[]) read("filename") == a ~ b);
}

void rename(in char[] from, in char[] to);
Rename file from to to.

Throws:
FileException on error.

void remove(in char[] name);
Delete file name.

Throws:
FileException on error.

ulong getSize(in char[] name);
Get size of file name.

Throws:
FileException on error (e.g., file not found).

void getTimes(in 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.

d_time lastModified(in char[] name);
Returns the time of the last modification of file name. If the file does not exist, throws a FileException.

d_time lastModified(in char[] name, d_time returnIfMissing);
Returns the time of the last modification of file name. If the file does not exist, returns returnIfMissing.

A frequent usage pattern occurs in build automation tools such as make or ant. To check whether file target must be rebuilt from file source (i.e., target is older than source or does not exist), use the comparison below. The code throws a FileException if source does not exist (as it should). On the other hand, the d_time.min default makes a non-existing target seem infinitely old so the test correctly prompts building it.

if (lastModified(source) >= lastModified(target, d_time.min))
{
    // must (re)build
}
else
{
    // target is up-to-date
}

bool exists(in char[] name);
Does file (or directory) name exist?

uint getAttributes(in char[] name);
Get file name attributes.

Throws:
FileException on error.

bool isdir(in char[] name);
Is name a directory?

Throws:
FileException if name doesn't exist.

bool isfile(in char[] name);
Is name a file?

Throws:
FileException if name doesn't exist.

void chdir(in char[] pathname);
Change directory to pathname.

Throws:
FileException on error.

void mkdir(in char[] pathname);
Make directory pathname.

Throws:
FileException on error.

void mkdirRecurse(in char[] pathname);
Make directory and all parent directories as needed.

void rmdir(in char[] pathname);
Remove directory pathname.

Throws:
FileException on error.

string 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

const bool isdir();
Return true if DirEntry is a directory.

const bool isfile();
Return !=0 if DirEntry is a file.

void listdir(in char[] pathname, bool delegate(DirEntry* de) callback);
For each file and directory DirEntry in pathname[], pass it to the callback delegate.

Note:
This function is being phased out. New code should use dirEntries (see below).

Parameters:
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);
 }

void copy(in char[] from, in char[] to);
Copy file from to file to. File timestamps are preserved.

void setTimes(in char[] name, d_time fta, d_time ftm);
Set access/modified times of file name.

Throws:
FileException on error.

void rmdirRecurse(in char[] pathname);
Remove directory and all of its content and subdirectories, recursively.

enum SpanMode;
Dictates directory spanning policy for dirEntries (see below).

shallow
Only spans one directory.

depth
Spans the directory depth-first, i.e. the content of any subdirectory is spanned before that subdirectory itself. Useful e.g. when recursively deleting files.

breadth
Spans the directory breadth-first, i.e. the content of any subdirectory is spanned right after that subdirectory itself.

DirIterator dirEntries(string path, SpanMode mode);
Iterates a directory using foreach. The iteration variable can be of type string if only the name is needed, or DirEntry if additional details are needed. The span mode dictates the how the directory is traversed. The name of the directory entry includes the path prefix.

Example:
 // Iterate a directory in depth
 foreach (string name; dirEntries("destroy/me", SpanMode.depth))
 {
     remove(name);
 }
 // Iterate a directory in breadth
 foreach (string name; dirEntries(".", SpanMode.breadth))
 {
     writeln(name);
 }
 // Iterate a directory and get detailed info about it
 foreach (DirEntry e; dirEntries("dmd-testing", SpanMode.breadth))
 {
     writeln(e.name, "\t", e.size);
 }

Select!(Types.length == 1,Types[0][],Tuple!(Types)[]) slurp(Types...)(string filename, in char[] format);
Reads an entire file into an array.

Example:
// Load file; each line is an int followed by comma, whitespace and a
// double.
auto a = slurp!(int, double)("filename", "%s, %s");

string[] listdir(in char[] 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(in char[] pathname, in char[] pattern);
string[] listdir(in char[] pathname, RegExp r);
Return all the files in the directory and its subdirectories that match pattern or regular expression r.

Parameters:
char[] pathname | Directory name
char[] 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(in char[] pathname, bool delegate(string filename) callback);
For each file and directory name in pathname[], pass it to the callback delegate.

Note:
This function is being phased out. New code should use dirEntries (see below).

Parameters:
bool delegate(string 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);
 }

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


std.format

This module implements the formatting functionality for strings and I/O. It's comparable to C99's vsprintf() and uses a similar format encoding scheme.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

class FormatError: object.Error;
Signals a mismatch between a format and its corresponding argument.

void formattedWrite(Writer, Char, A...)(Writer w, in Char[] fmt, A args);
Interprets variadic argument list args, formats them according to fmt, and sends the resulting characters to w. The encoding of the output is the same as Char. type Writer must satisfy std.range.isOutputRange!(Writer, Char).

The variadic arguments are normally consumed in order. POSIX-style positional parameter syntax is also supported. Each argument is formatted into a sequence of chars according to the format specification, and the characters are passed to w. As many arguments as specified in the format string are consumed and formatted. If there are fewer arguments than format specifiers, a FormatError is thrown. If there are more remaining arguments than needed by the format specification, they are ignored but only if at least one argument was formatted.

Parameters:
w | Output is sent do this writer. Typical output writers include std.range.Appender!string and std.stdio.BlockingTextWriter.
fmt | Format string.
args | 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.

The format string has the following grammar:

Flags affect formatting depending on the specifier as follows.
Flag Types affected Semantics
'-' numeric Left justify the result in the field. It overrides any 0 flag.
'+' numeric Prefix positive numbers in a signed conversion with a +. It overrides any space flag.
'#' integral ('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.
'#' integral ('x', 'X') If non-zero, prefix result with 0x (0X).
'#' floating Always insert the decimal point and print trailing zeros.
'#' numeric ('0') Use leading zeros to pad rather than spaces (except for the floating point values nan and infinity). Ignore if there's a Precision.
' ' integral ('d') 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 main()
{
    auto writer = appender!string();
    formattedWrite(writer, "%s is the ultimate %s.", 42, "answer");
    assert(writer.data == "42 is the ultimate answer.");
    // Clear the writer
    writer = appender!string();
    formattedWrite(writer, "Date: %2$s %1$s", "October", 5);
    assert(writer.data == "Date: 5 October");
}
The positional and non-positional styles can be mixed in the same format string. (POSIX leaves this behavior undefined.) The internal counter for non-positional parameters tracks the next parameter after the largest positional parameter already used.

void formattedRead(R, Char, S...)(ref R r, const(Char)[] fmt, S args);
Reads characters from input range r, converts them according to fmt, and writes them to args.

Example:
string s = "hello!124:34.5";
string a;
int b;
double c;
formattedRead(s, "%s!%s:%s", &a, &b, &c);
assert(a == "hello" && b == 124 && c == 34.5);

struct FormatSpec(Char);
A compiled version of an individual format specifier, backwards compatible with printf specifiers.

int width;
Minimum width, default 0.

int precision;
Precision. Its semantics depends on the argument type. For floating point numbers, precision dictates the number of decimals printed.

int DYNAMIC;
Special value for width and precision. DYNAMIC width or precision means that they were specified with '*' in the format string and are passed at runtime through the varargs.

int UNSPECIFIED;
Special value for precision, meaning the format specifier contained no explicit precision.

char spec;
The actual format specifier, 's' by default.

ubyte index;
Index of the argument for positional parameters, from 1 to ubyte.max. (0 means not used).

bool flDash;
The format specifier contained a '-' (printf compatibility).

bool flZero;
The format specifier contained a '0' (printf compatibility).

bool flSpace;
The format specifier contained a ' ' (printf compatibility).

bool flPlus;
The format specifier contained a '+' (printf compatibility).

bool flHash;
The format specifier contained a '#' (printf compatibility).

const(Char)[] nested;
In case of a compound format specifier starting with "%(" and ending with "%)", nested contains the string contained within the two separators.

const(Char)[] trailing;
trailing contains the rest of the format string.

__ctor;
Given a string format specification fmt, parses a format specifier. The string is assumed to start with the character immediately following the '%'. The string is advanced to right after the end of the format specifier.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
void[] is formatted like ubyte[].

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
enum is formatted like its base value.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Integrals are formatted like printf does.

void formatValue(Writer, D, Char)(Writer w, D obj, ref FormatSpec!(Char) f);
Floating-point values are formatted like printf does.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
bool is formatted as "true" or "false" with %s and as "1" or "0" with integral-specific format specs.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Individual characters (char, wchar, or dchar) are formatted as Unicode characters with %s and as integers with integral-specific format specs.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Strings are formatted like printf does.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Input ranges are formatted like arrays.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
void[0] is formatted as "[]".

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Pointers are formatted as hex integers.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Objects are formatted by calling toString.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Interfaces are formatted by casting to Object and then calling toString.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Associative arrays are formatted by using ':' and ' ' as separators.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Structs are formatted using by calling toString member function of the struct. toString must have one of the following signatures:
   void toString(void delegate(const(char)[]) sink, FormatSpec fmt);
   void toString(void delegate(const(char)[]) sink, string fmt);

void formatValue(Writer, T, Char)(Writer w, ref T val, ref FormatSpec!(Char) f);
Static-size arrays are formatted just like arrays.

void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!(Char) f);
Delegates are formatted by 'Attributes ReturnType delegate(Parameters)'

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads an array (except for string types) and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads a string and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads an integral value and returns it.

T unformatValue(T, Range, Char)(ref Range input, ref FormatSpec!(Char) spec);
Reads a floating-point value and returns it.

Copyright Digital Mars 2000-. | Page generated by Ddoc.


std.functional

Functions that manipulate other functions.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

template unaryFun(alias funbody,bool byRef = false,string parmName = "a")
Transforms a string representing an expression into a unary function. The string must use symbol name a as the parameter.

Example:
alias unaryFun!("(a & 1) == 0") isEven;
assert(isEven(2) && !isEven(1));

template binaryFun(alias funbody,string parm1Name = "a",string parm2Name = "b")
Transforms a string representing an expression into a Boolean binary predicate. The string must use symbol names a and b as the compared elements.

Example:
alias binaryFun!("a < b") less;
assert(less(1, 2) && !less(2, 1));
alias binaryFun!("a > b") greater;
assert(!greater("1", "2") && greater("2", "1"));

template not(alias pred)
Negates predicate pred.

Example:
string a = "   Hello, world!";
assert(find!(not!isspace)(a) == "Hello, world!");

template curry(alias fun,alias arg)
Curries fun by tying its first argument to a particular value.

Example:
int fun(int a, int b) { return a + b; }
alias curry!(fun, 5) fun5;
assert(fun5(6) == 11);
Note that in most cases you'd use an alias instead of a value assignment. Using an alias allows you to curry template functions without committing to a particular type of the function.

template adjoin(F...) if (F.length)
Takes multiple functions and adjoins them together. The result is a std.typecons.Tuple with one element per passed-in function. Upon invocation, the returned tuple is the adjoined results of all functions.

Example:
static bool f1(int a) { return a != 0; }
static int f2(int a) { return a / 2; }
auto x = adjoin!(f1, f2)(5);
assert(is(typeof(x) == Tuple!(bool, int)));
assert(x[0] == true && x[1] == 2);

template compose(fun...)
Composes passed-in functions fun[0], fun[1], ... returning a function f(x) that in turn returns fun[0](fun[1](...(x))).... Each function can be a regular functions, a delegate, or a string.

Example:
// First split a string in whitespace-separated tokens and then
// convert each token into an integer
assert(compose!(map!(to!(int)), split)("1 2 3") == [1, 2, 3]);

template pipe(fun...)
Pipes functions in sequence. Offers the same functionality as compose, but with functions specified in reverse order. This may lead to more readable code in some situation because the order of execution is the same as lexical order.

Example:
// Read an entire text file, split the resulting string in
// whitespace-separated tokens, and then convert each token into an
// integer
int[] a = pipe!(readText, split, map!(to!(int)))("file.txt");

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


core.memory

The memory module provides an interface to the garbage collector and to any other OS or API-level memory management facilities.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/memory.d

struct GC;
This struct encapsulates all garbage collection functionality for the D programming language.

static void enable();
Enables automatic garbage collection behavior if collections have previously been suspended by a call to disable. This function is reentrant, and must be called once for every call to disable before automatic collections are enabled.

static void disable();
Disables automatic garbage collections performed to minimize the process footprint. Collections may continue to occur in instances where the implementation deems necessary for correct program behavior, such as during an out of memory condition. This function is reentrant, but enable must be called once for each call to disable.

static void collect();
Begins a full collection. While the meaning of this may change based on the garbage collector implementation, typical behavior is to scan all stack segments for roots, mark accessible memory blocks as alive, and then to reclaim free space. This action may need to suspend all running threads for at least part of the collection process.

static void minimize();
Indicates that the managed memory space be minimized by returning free physical memory to the operating system. The amount of free memory returned depends on the allocator design and on program behavior.

enum BlkAttr;
Elements for a bit field representing memory block attributes. These are manipulated via the getAttr, setAttr, clrAttr functions.

FINALIZE
Finalize the data in this block on collect.

NO_SCAN
Do not scan through this block on collect.

NO_MOVE
Do not move this memory block on collect.

APPENDABLE
This block contains the info to allow appending.

alias BlkInfo;
Contains aggregate information about a block of managed memory. The purpose of this struct is to support a more efficient query style in instances where detailed information is needed.

base = A pointer to the base of the block in question. size = The size of the block, calculated from base. attr = Attribute bits set on the memory block.

static uint getAttr(in void* p);
Returns a bit field representing all block attributes set for the memory referenced by p. If p references memory not originally allocated by this garbage collector, points to the interior of a memory block, or if p is null, zero will be returned.

Parameters:
void* p A pointer to the root of a valid memory block or to null.

Returns:
A bit field containing any bits set for the memory block referenced by p or zero on error.

static uint setAttr(in void* p, uint a);
Sets the specified bits for the memory references by p. If p references memory not originally allocated by this garbage collector, points to the interior of a memory block, or if p is null, no action will be performed.

Parameters:
void* p A pointer to the root of a valid memory block or to null.
uint a A bit field containing any bits to set for this memory block.

The result of a call to getAttr after the specified bits have been set.

static uint clrAttr(in void* p, uint a);
Clears the specified bits for the memory references by p. If p references memory not originally allocated by this garbage collector, points to the interior of a memory block, or if p is null, no action will be performed.

Parameters:
void* p | A pointer to the root of a valid memory block or to null.
uint a | A bit field containing any bits to clear for this memory block.

Returns:
The result of a call to getAttr after the specified bits have been cleared.

static void* malloc(size_t sz, uint ba = 0);
Requests an aligned block of managed memory from the garbage collector. This memory may be deleted at will with a call to free, or it may be discarded and cleaned up automatically during a collection run. If allocation fails, this function will call onOutOfMemory which is expected to throw an OutOfMemoryException.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory or null if insufficient memory is available.

Throws:
OutOfMemoryException on allocation failure.

static BlkInfo qalloc(size_t sz, uint ba = 0);
Requests an aligned block of managed memory from the garbage collector. This memory may be deleted at will with a call to free, or it may be discarded and cleaned up automatically during a collection run. If allocation fails, this function will call onOutOfMemory which is expected to throw an OutOfMemoryException.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
Information regarding the allocated memory block or BlkInfo.init on error.

Throws:
OutOfMemoryException on allocation failure.

static void* calloc(size_t sz, uint ba = 0);
Requests an aligned block of managed memory from the garbage collector, which is initialized with all bits set to zero. This memory may be deleted at will with a call to free, or it may be discarded and cleaned up automatically during a collection run. If allocation fails, this function will call onOutOfMemory which is expected to throw an OutOfMemoryException.

Parameters:
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory or null if insufficient memory is available.

Throws:
OutOfMemoryException on allocation failure.

static void* realloc(void* p, size_t sz, uint ba = 0);
If sz is zero, the memory referenced by p will be deallocated as if by a call to free. A new memory block of size sz will then be allocated as if by a call to malloc, or the implementation may instead resize the memory block in place. The contents of the new memory block will be the same as the contents of the old memory block, up to the lesser of the new and old sizes. Note that existing memory will only be freed by realloc if sz is equal to zero. The garbage collector is otherwise expected to later reclaim the memory block if it is unused. If allocation fails, this function will call onOutOfMemory which is expected to throw an OutOfMemoryException. If p references memory not originally allocated by this garbage collector, or if it points to the interior of a memory block, no action will be taken. If ba is zero (the default) and p references the head of a valid, known memory block then any bits set on the current block will be set on the new block if a reallocation is required. If ba is not zero and p references the head of a valid, known memory block then the bits in ba will replace those on the current memory block and will also be set on the new block if a reallocation is required.

Parameters:
void* p | A pointer to the root of a valid memory block or to null.
size_t sz | The desired allocation size in bytes.
uint ba | A bitmask of the attributes to set on this block.

Returns:
A reference to the allocated memory on success or null if sz is zero. On failure, the original value of p is returned.

Throws:
OutOfMemoryException on allocation failure.

static size_t extend(void* p, size_t mx, size_t sz);
Requests that the managed memory block referenced by p be extended in place by at least mx bytes, with a desired extension of sz bytes. If an extension of the required size is not possible, if p references memory not originally allocated by this garbage collector, or if p points to the interior of a memory block, no action will be taken.

Parameters:
size_t mx | The minimum extension size in bytes.
size_t sz | The desired extension size in bytes.

Returns:
The size in bytes of the extended memory block referenced by p or zero if no extension occurred.

static size_t reserve(size_t sz);
Requests that at least sz bytes of memory be obtained from the operating system and marked as free.

Parameters:
size_t sz The desired size in bytes.

Returns:
The actual number of bytes reserved or zero on error.

static void free(void* p);
Deallocates the memory referenced by p. If p is null, no action occurs. If p references memory not originally allocated by this garbage collector, or if it points to the interior of a memory block, no action will be taken. The block will not be finalized regardless of whether the FINALIZE attribute is set. If finalization is desired, use delete instead.

Parameters:
void* p A pointer to the root of a valid memory block or to null.

static void* addrOf(in void* p);
Returns the base address of the memory block containing p. This value is useful to determine whether p is an interior pointer, and the result may be passed to routines such as sizeOf which may otherwise fail. If p references memory not originally allocated by this garbage collector, if p is null, or if the garbage collector does not support this operation, null will be returned.

Parameters:
void* p A pointer to the root or the interior of a valid memory block or to null.

Returns:
The base address of the memory block referenced by p or null on error.

static size_t sizeOf(in void* p);
Returns the true size of the memory block referenced by p. This value represents the maximum number of bytes for which a call to realloc may resize the existing block in place. If p references memory not originally allocated by this garbage collector, points to the interior of a memory block, or if p is null, zero will be returned.

Parameters:
void* p A pointer to the root of a valid memory block or to null.

Returns:
The size in bytes of the memory block referenced by p or zero on error.

static BlkInfo query(in void* p);
Returns aggregate information about the memory block containing p. If p references memory not originally allocated by this garbage collector, if p is null, or if the garbage collector does not support this operation, BlkInfo.init will be returned. Typically, support for this operation is dependent on support for addrOf.

Parameters:
void* p A pointer to the root or the interior of a valid memory block or to null.

Returns:
Information regarding the memory block referenced by p or BlkInfo.init on error.

static void addRoot(in void* p);
Adds the memory address referenced by p to an internal list of roots to be scanned during a collection. If p is null, no operation is performed.

Parameters:
void* p A pointer to a valid memory address or to null.

static void addRange(in void* p, size_t sz);
Adds the memory block referenced by p and of size sz to an internal list of ranges to be scanned during a collection. If p is null, no operation is performed.

Parameters:
void* p | A pointer to a valid memory address or to null.
size_t sz | The size in bytes of the block to add. If sz is zero then the no operation will occur. If p is null then sz must be zero.

static void removeRoot(in void* p);
Removes the memory block referenced by p from an internal list of roots to be scanned during a collection. If p is null or does not represent a value previously passed to add(void*) then no operation is performed.

p = A pointer to a valid memory address or to null.

static void removeRange(in void* p);
Removes the memory block referenced by p from an internal list of ranges to be scanned during a collection. If p is null or does not represent a value previously passed to add(void*, size_t) then no operation is performed.

Parameters:
void* p A pointer to a valid memory address or to null.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


std.getopt

Processing of command line options.

The getopt module implements a getopt function, which adheres to the POSIX syntax for command line options. GNU extensions are supported in the form of long options introduced by a double dash ("--"). Support for bundling of command line options, as was the case with the more traditional single-letter approach, is provided but not enabled by default.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Credits:
This module and its documentation are inspired by Perl's Getopt::Long module. The syntax of D's getopt is simpler than its Perl counterpart because getopt infers the expected parameter types from the static types of the passed-in pointers.

void getopt(T...)(ref string[] args, T opts);
Synopsis:
import std.getopt;

string data = "file.dat";
int length = 24;
bool verbose;

void main(string[] args)
{
  getopt(
    args,
    "length",  &length,    // numeric
    "file",    &data,      // string
    "verbose", &verbose);  // flag
  ...
}
The getopt function takes a reference to the command line (as received by main) as its first argument, and an unbounded number of pairs of strings and pointers. Each string is an option meant to "fill" the value pointed-to by the pointer to its right (the "bound" pointer). The option string in the call to getopt should not start with a dash.

In all cases, the command-line options that were parsed and used by getopt are removed from args. Whatever in the arguments did not look like an option is left in args for further processing by the program. Values that were unaffected by the options are not touched, so a common idiom is to initialize options to their defaults and then invoke getopt. If a command-line argument is recognized as an option with a parameter and the parameter cannot be parsed properly (e.g. a number is expected but not present), a ConvException exception is thrown.

Depending on the type of the pointer being bound, getopt recognizes the following kinds of options:

  1. Boolean options. These are the simplest options; all they do is set a Boolean to true:

      bool verbose, debugging;
  getopt(args, "verbose", &verbose, "debug", &debugging);
  2. Numeric options. If an option is bound to a numeric type, a number is expected as the next option, or right within the option separated with an "=" sign:

      uint timeout;
  getopt(args, "timeout", &timeout);
    To set timeout to 5, invoke the program with either --timeout=5 or --timeout 5.

    • Incremental options. If an option name has a "+" suffix and is bound to a numeric type, then the option's value tracks the number of times the option occurred on the command line:

        uint paranoid;
  getopt(args, "paranoid+", &paranoid);
      Invoking the program with "--paranoid --paranoid --paranoid" will set paranoid to 3. Note that an incremental option never expects a parameter, e.g. in the command line "--paranoid 42 --paranoid", the "42" does not set paranoid to 42; instead, paranoid is set to 2 and "42" is not considered as part of the normal program arguments.

  3. String options. If an option is bound to a string, a string is expected as the next option, or right within the option separated with an "=" sign:

    string outputFile;
getopt(args, "output", &outputFile);
    Invoking the program with "--output=myfile.txt" or "--output myfile.txt" will set outputFile to "myfile.txt".
    4. If you want to pass a string containing spaces, you need to use the quoting that is appropriate to your shell, e.g. --output='my file.txt'.

  4. Array options. If an option is bound to an array, a new element is appended to the array each time the option occurs:

    string[] outputFiles;
getopt(args, "output", &outputFiles);
    Invoking the program with "--output=myfile.txt --output=yourfile.txt" or "--output myfile.txt --output yourfile.txt" will set outputFiles to [ "myfile.txt", "yourfile.txt" ] .

  5. Hash options. If an option is bound to an associative array, a string of the form "name=value" is expected as the next option, or right within the option separated with an "=" sign:

    double[string] tuningParms;
getopt(args, "tune", &tuningParms);
    Invoking the program with e.g. "--tune=alpha=0.5 --tune beta=0.6" will set tuningParms to [ "alpha" : 0.5, "beta" : 0.6 ].
    6. In general, keys and values can be of any parsable types.

  6. Delegate options. An option can be bound to a delegate with the signature void delegate(), void delegate(string option) or void delegate(string option, string value).

    • In the void delegate() case, the delegate is invoked whenever the option is seen.
    • In the void delegate(string option) case, the option string (without the leading dash(es)) is passed to the delegate. After that, the option string is considered handled and removed from the options array.

      • void main(string[] args)
{
  uint verbosityLevel = 1;
  void myHandler(string option)
  {
    if (option == "quiet")
    {
      verbosityLevel = 0;
    }
    else
    {
      assert(option == "verbose");
      verbosityLevel = 2;
    }
  }
  getopt(args, "verbose", &myHandler, "quiet", &myHandler);
}
    • In the void delegate(string option, string value) case, the option string is handled as an option with one argument, and parsed accordingly. The option and its value are passed to the delegate. After that, whatever was passed to the delegate is considered handled and removed from the list.

      • void main(string[] args)
{
  uint verbosityLevel = 1;
  void myHandler(string option, string value)
  {
    switch (value)
    {
      case "quiet": verbosityLevel = 0; break;
      case "verbose": verbosityLevel = 2; break;
      case "shouting": verbosityLevel = verbosityLevel.max; break;
      default :
        stderr.writeln("Dunno how verbose you want me to be by saying ",
          value);
        exit(1);
    }
  }
  getopt(args, "verbosity", &myHandler);
}

Options with multiple names

Sometimes option synonyms are desirable, e.g. "--verbose", "--loquacious", and "--garrulous" should have the same effect. Such alternate option names can be included in the option specification, using "|" as a separator:

bool verbose;
getopt(args, "verbose|loquacious|garrulous", &verbose);
Case

By default options are case-insensitive. You can change that behavior by passing getopt the caseSensitive directive like this:

bool foo, bar;
getopt(args,
    std.getopt.config.caseSensitive,
    "foo", &foo,
    "bar", &bar);
In the example above, "--foo", "--bar", "--FOo", "--bAr" etc. are recognized. The directive is active til the end of getopt, or until the converse directive caseInsensitive is encountered:

bool foo, bar;
getopt(args,
    std.getopt.config.caseSensitive,
    "foo", &foo,
    std.getopt.config.caseInsensitive,
    "bar", &bar);
The option "--Foo" is rejected due to std.getopt.config.caseSensitive, but not "--Bar", "--bAr" etc. because the directive std.getopt.config.caseInsensitive turned sensitivity off before option "bar" was parsed.

"Short" versus "long" options

Traditionally, programs accepted single-letter options preceded by only one dash (e.g. -t). getopt accepts such parameters seamlessly. When used with a double-dash (e.g. --t), a single-letter option behaves the same as a multi-letter option. When used with a single dash, a single-letter option is accepted. If the option has a parameter, that must be "stuck" to the option without any intervening space or "=":

uint timeout;
getopt(args, "timeout|t", &timeout);
To set timeout to 5, use either of the following: --timeout=5, --timeout 5, --t=5, --t 5, or -t5. Forms such as -t 5 and -timeout=5 will be not accepted.

For more details about short options, refer also to the next section.

Bundling

Single-letter options can be bundled together, i.e. "-abc" is the same as "-a -b -c". By default, this confusing option is turned off. You can turn it on with the std.getopt.config.bundling directive:

bool foo, bar;
getopt(args,
    std.getopt.config.bundling,
    "foo|f", &foo,
    "bar|b", &bar);
In case you want to only enable bundling for some of the parameters, bundling can be turned off with std.getopt.config.noBundling.

Passing unrecognized options through

If an application needs to do its own processing of whichever arguments getopt did not understand, it can pass the std.getopt.config.passThrough directive to getopt:

bool foo, bar;
getopt(args,
    std.getopt.config.passThrough,
    "foo", &foo,
    "bar", &bar);
An unrecognized option such as "--baz" will be found untouched in args after getopt returns.

Options Terminator

A lonesome double-dash terminates getopt gathering. It is used to separate program options from other parameters (e.g. options to be passed to another program). Invoking the example above with "--foo -- --bar" parses foo but leaves "--bar" in args. The double-dash itself is removed from the argument array.

enum config;
Configuration options for getopt. You can pass them to getopt in any position, except in between an option string and its bound pointer.

caseSensitive
Turns case sensitivity on

caseInsensitive
Turns case sensitivity off

bundling
Turns bundling on

noBundling
Turns bundling off

passThrough
Pass unrecognized arguments through

noPassThrough
Signal unrecognized arguments as errors

stopOnFirstNonOption
Stop at first argument that does not look like an option

dchar optionChar;
The option character. Defaults to '-' but it can be assigned to prior to calling getopt.

string endOfOptions;
The string that conventionally marks the end of all options. Defaults to "--" but can be assigned to prior to calling getopt. Assigning an empty string to endOfOptions effectively disables it.

dchar assignChar;
The assignment character used in options with parameters. Defaults to '=' but can be assigned to prior to calling getopt.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


std.gregorian

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Copyright Andrei Alexandrescu 2008 - 2009. | 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

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(in 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.

Parameters:
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.json

JavaScript Object Notation

License:
Boost License 1.0.

Authors:
Jeremie Pelletier

References:
http://json.org/

enum JSON_TYPE;
JSON value types

struct JSONValue;
JSON value node

JSONValue parseJSON(T)(T json, int maxDepth = -1);
Parses a serialized string and returns a tree of JSON values.

string toJSON(in JSONValue* root);
Takes a tree of JSON values and returns the serialized string.

class JSONException: object.Exception;
Exception thrown on JSON errors

Copyright Jeremie Pelletier 2008 - 2009. | Page generated by Ddoc.


std.math

Elementary mathematical functions

Contains the elementary mathematical functions (powers, roots, and trignometric functions), and low-level floating-point operations. Mathematical special functions are available in std.mathspecial.

The functionality closely follows the IEEE754-2008 standard for floating-point arithmetic, including the use of camelCase names rather than C99-style lower case names. All of these functions behave correctly when presented with an infinity or NaN.

Unlike C, there is no global 'errno' variable. Consequently, almost all of these functions are pure nothrow.

Status:
The gamma and error functions have been superceded by improved versions in std.mathspecial. They will be officially deprecated in std.math in DMD2.055. The semantics and names of feqrel and approxEqual will be revised.

License:
Boost License 1.0.

Authors:
Walter Bright, Don Clugston

real E;
e

real LOG2T;
log210

real LOG2E;
log2e

real LOG2;
log102

real LOG10E;
log10e

real LN2;
ln 2

real LN10;
ln 10

real PI;
π

real PI_2;
π / 2

real PI_4;
π / 4

real M_1_PI;
1 / π

real M_2_PI;
2 / π

real M_2_SQRTPI;
2 / √π

real SQRT2;
√2

real SQRT1_2;
√½

Num abs(Num)(Num x);
real abs(Num)(Num y);
Calculates the absolute value

For complex numbers, abs(z) = sqrt( z.re2 + z.im2 ) = hypot(z.re, z.im).

pure nothrow @safe creal conj(creal z);
pure nothrow @safe 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

pure nothrow @safe 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.

pure nothrow @safe 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.

pure nothrow @safe creal sin(creal z);
pure nothrow @safe 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(θ).

pure nothrow @safe creal cos(creal z);
pure nothrow @safe real cos(ireal y);
cosine, complex and imaginary

cos(z) = cos(z.re)*cosh(z.im) - sin(z.re)*sinh(z.im)i

pure nothrow @trusted 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

pure nothrow @safe real acos(real x);
pure nothrow @safe double acos(double x);
pure nothrow @safe float acos(float 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

pure nothrow @safe real asin(real x);
pure nothrow @safe double asin(double x);
pure nothrow @safe float asin(float 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

pure nothrow @safe real atan(real x);
pure nothrow @safe double atan(double x);
pure nothrow @safe float atan(float 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

pure nothrow @trusted real atan2(real y, real x);
pure nothrow @safe double atan2(double y, double x);
pure nothrow @safe float atan2(float y, float 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

pure nothrow @safe real cosh(real x);
pure nothrow @safe double cosh(double x);
pure nothrow @safe float cosh(float x);
Calculates the hyperbolic cosine of x.

Special Values
x cosh(x) invalid?
±∞ ±0.0 no

pure nothrow @safe real sinh(real x);
pure nothrow @safe double sinh(double x);
pure nothrow @safe float sinh(float x);
Calculates the hyperbolic sine of x.

Special Values
x | sinh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±∞ no

pure nothrow @safe real tanh(real x);
pure nothrow @safe double tanh(double x);
pure nothrow @safe float tanh(float x);
Calculates the hyperbolic tangent of x.

Special Values
x | tanh(x) | invalid?
±0.0 | ±0.0 | no
±∞ ±1.0 no

pure nothrow @safe real acosh(real x);
pure nothrow @safe double acosh(double x);
pure nothrow @safe float acosh(float 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
+∞ +∞

pure nothrow @safe real asinh(real x);
pure nothrow @safe double asinh(double x);
pure nothrow @safe float asinh(float 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
±∞ ±∞

pure nothrow @safe real atanh(real x);
pure nothrow @safe double atanh(double x);
pure nothrow @safe float atanh(float 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

pure nothrow @safe 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);
Compute square root of x.

Special Values
x | sqrt(x) | invalid?
-0.0 | -0.0 | no
<0.0 | NAN | yes
+∞ +∞ no

double sqrt(double x);
ditto

Compute square root of x.

Special Values
x | sqrt(x) | invalid?
-0.0 | -0.0 | no
<0.0 | NAN | yes
+∞ +∞ no

real sqrt(real x);
ditto

Compute square root of x.

Special Values
x | sqrt(x) | invalid?
-0.0 | -0.0 | no
<0.0 | NAN | yes
+∞ +∞ no

pure nothrow @safe real exp(real x);
pure nothrow @safe double exp(double x);
pure nothrow @safe float exp(float x);
Calculates ex.

Special Values
x | ex
+∞ +∞
-∞ +0.0
NAN | NAN

pure nothrow @trusted 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

pure nothrow @trusted real exp2(real x);
Calculates 2x.

Special Values
x | exp2(x)
+∞ +∞
-∞ +0.0
NAN | NAN

pure nothrow @trusted 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.

pure nothrow @trusted 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

nothrow @trusted 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 cast(int)logb(x).

Special Values
x | ilogb(x) | Range error?
0 | FP_ILOGB0 | yes
±∞ int.max no
NAN | FP_ILOGBNAN | no

pure nothrow @safe real ldexp(real n, int exp);
Compute n * 2exp

References:
frexp

pure nothrow @safe 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

pure nothrow @safe 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

pure nothrow @safe 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

pure nothrow @safe 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

nothrow @trusted 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

nothrow @trusted real modf(real x, ref real y);
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

nothrow @trusted 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

nothrow @trusted 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

pure nothrow @safe real fabs(real x);
Returns |x|

Special Values
x | fabs(x)
±0.0 | +0.0
±∞ +∞

pure nothrow @safe 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

nothrow @trusted real erf(real x);
Returns the error function of x.

error function

nothrow @trusted real erfc(real x);
Returns the complementary error function of x, which is 1 - erf(x).

complementary error function

nothrow @trusted 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

nothrow @trusted 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

nothrow @trusted real ceil(real x);
Returns the value of x rounded upward to the next integer (toward positive infinity).

nothrow @trusted real floor(real x);
Returns the value of x rounded downward to the next integer (toward negative infinity).

nothrow @trusted 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.

pure nothrow @safe 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.

pure nothrow @trusted 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.

nothrow @trusted 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.

nothrow @trusted 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.

nothrow @trusted real trunc(real x);
Returns the integer portion of x, dropping the fractional portion.

This is also known as "chop" rounding.

nothrow @trusted real remainder(real x, real y);
nothrow @trusted 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

struct IeeeFlags;
IEEE exception status flags ('sticky bits')

These flags indicate that an exceptional floating-point condition has occurred. They indicate that a NaN or an infinity has been generated, that a result is inexact, or that a signalling NaN has been encountered. If floating-point exceptions are enabled (unmasked), a hardware exception will be generated instead of setting these flags.

Example:
    real a=3.5;
    // Set all the flags to zero
    resetIeeeFlags();
    assert(!ieeeFlags.divByZero);
    // Perform a division by zero.
    a/=0.0L;
    assert(a==real.infinity);
    assert(ieeeFlags.divByZero);
    // Create a NaN
    a*=0.0L;
    assert(ieeeFlags.invalid);
    assert(isNaN(a));

    // Check that calling func() has no effect on the
    // status flags.
    IeeeFlags f = ieeeFlags;
    func();
    assert(ieeeFlags == f);

bool inexact();
The result cannot be represented exactly, so rounding occured. (example: x = sin(0.1); )

bool underflow();
A zero was generated by underflow (example: x = real.min*real.epsilon/2;)

bool overflow();
An infinity was generated by overflow (example: x = real.max*2;)

bool divByZero();
An infinity was generated by division by zero (example: x = 3/0.0; )

bool invalid();
A machine NaN was generated. (example: x = real.infinity * 0.0; )

void resetIeeeFlags();
Set all of the floating-point status flags to false.

IeeeFlags ieeeFlags();
Return a snapshot of the current state of the floating-point status flags.

struct FloatingPointControl;
Control the Floating point hardware

Change the IEEE754 floating-point rounding mode and the floating-point hardware exceptions.

By default, the rounding mode is roundToNearest and all hardware exceptions are disabled. For most applications, debugging is easier if the division by zero, overflow, and invalid operation exceptions are enabled. These three are combined into a severeExceptions value for convenience. Note in particular that if invalidException is enabled, a hardware trap will be generated whenever an uninitialized floating-point variable is used.

All changes are temporary. The previous state is restored at the end of the scope.

Example:
  {
    // Enable hardware exceptions for division by zero, overflow to infinity,
    // invalid operations, and uninitialized floating-point variables.

    FloatingPointControl fpctrl;
    fpctrl.enableExceptions(FloatingPointControl.severeExceptions);

    double y = x*3.0; // will generate a hardware exception, if x is uninitialized.
    //
    fpctrl.rounding = FloatingPointControl.roundUp;

    // The hardware exceptions will be disabled when leaving this scope.
    // The original rounding mode will also be restored.
  }

severeExceptions
Severe = The overflow, division by zero, and invalid exceptions.

void enableExceptions(uint exceptions);
Enable (unmask) specific hardware exceptions. Multiple exceptions may be ORed together.

void disableExceptions(uint exceptions);
Disable (mask) specific hardware exceptions. Multiple exceptions may be ORed together.

void rounding(RoundingMode newMode);
Change the floating-point hardware rounding mode

static uint enabledExceptions();
Return the exceptions which are currently enabled (unmasked)

static RoundingMode rounding();
Return the currently active rounding mode

pure nothrow @trusted bool isNaN(real x);
Returns !=0 if e is a NaN.

pure nothrow @trusted 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).

pure nothrow @trusted int isSubnormal(float f);
pure nothrow @trusted int isSubnormal(double d);
pure nothrow @trusted int isSubnormal(real x);
Is number subnormal? (Also called "denormal".) Subnormals have a 0 exponent and a 0 most significant mantissa bit.

pure nothrow @trusted bool isInfinity(real x);
Return !=0 if e is ±∞.

pure nothrow @trusted 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'.

pure nothrow @trusted int signbit(real x);
Return 1 if sign bit of e is set, 0 if not.

pure nothrow @trusted real copysign(real to, real from);
Return a value composed of to with from's sign bit.

F sgn(F)(F x);
Returns -1 if x < 0, x if x == 0, 1 if x > 0, and NAN if x==NAN.

pure nothrow @trusted real NaN(ulong payload);
Create a quiet NAN, storing an integer inside the payload.

For floats, the largest possible payload is 0x3F_FFFF. For doubles, it is 0x3_FFFF_FFFF_FFFF. For 80-bit or 128-bit reals, it is 0x3FFF_FFFF_FFFF_FFFF.

pure nothrow @trusted ulong getNaNPayload(real x);
Extract an integral payload from a NAN.

Returns:
the integer payload as a ulong.

For floats, the largest possible payload is 0x3F_FFFF. For doubles, it is 0x3_FFFF_FFFF_FFFF. For 80-bit or 128-bit reals, it is 0x3FFF_FFFF_FFFF_FFFF.

pure nothrow @trusted real nextUp(real x);
pure nothrow @trusted double nextUp(double x);
pure nothrow @trusted 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_normal*real.epsilon
real.max ∞
∞ ∞
NAN | NAN

pure nothrow @safe real nextDown(real x);
pure nothrow @safe double nextDown(double x);
pure nothrow @safe 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_normal*real.epsilon
-real.max -∞
-∞ -∞
NAN | NAN

T nextafter(T)(T x, T 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.

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.

pure nothrow @safe 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

pure nothrow @safe real fmax(real x, real y);
Returns the larger of x and y.

pure nothrow @safe real fmin(real x, real y);
Returns the smaller of x and y.

pure nothrow @safe 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.

Unqual!(F) pow(F, G)(F x, G n);
Compute the value of x n, where n is an integer

typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n);
Compute the value of an integer x, raised to the power of a positive integer n.

If both x and n are 0, the result is 1. If n is negative, an integer divide error will occur at runtime, regardless of the value of x.

real pow(I, F)(I x, F y);
Computes integer to floating point powers.

Unqual!(Largest!(F,G)) pow(F, G)(F x, G y);
Calculates xy.

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

pure nothrow @trusted real poly(real x, const real[] A);
Evaluate polynomial A(x) = a0 + a1x + a2x2 + a3x3; ...

Uses Horner's rule A(x) = a0 + x(a1 + x(a2 + x(a3 + ...)))

Parameters:
real[] A array of coefficients a0, a1, etc.

bool approxEqual(T, U, V)(T lhs, U rhs, V maxRelDiff, V maxAbsDiff = 1e-05);
Computes whether lhs is approximately equal to rhs admitting a maximum relative difference maxRelDiff and a maximum absolute difference maxAbsDiff.

If the two inputs are ranges, approxEqual returns true if and only if the ranges have the same number of elements and if approxEqual evaluates to true for each pair of elements.

bool approxEqual(T, U)(T lhs, U rhs);
Returns approxEqual(lhs, rhs, 1e-2, 1e-5).

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.mathspecial

Mathematical Special Functions

The technical term 'Special Functions' includes several families of transcendental functions, which have important applications in particular branches of mathematics and physics.

The gamma and related functions, and the error function are crucial for mathematical statistics. The Bessel and related functions arise in problems involving wave propagation (especially in optics). Other major categories of special functions include the elliptic integrals (related to the arc length of an ellipse), and the hypergeometric functions.

Status:
Many more functions will be added to this module. The naming convention for the distribution functions (gammaIncomplete, etc) is not yet finalized and will probably change.

License:
Boost License 1.0.

Authors:
Stephen L. Moshier (original C code). Conversion to D by Don Clugston

real gamma(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)
NAN | NAN
±0.0 ±∞
integer > 0 | (x-1)!
integer < 0 | NAN
+∞ +∞
-∞ NAN

real logGamma(real x);
Natural logarithm of the gamma function, Γ(x)

Returns the base e (2.718...) logarithm of the absolute value of the gamma function of the argument.

For reals, logGamma is equivalent to log(fabs(gamma(x))).

Special Values
x | logGamma(x)
NAN | NAN
integer <= 0 +∞
±∞ +∞

real sgnGamma(real x);
The sign of Γ(x).

Returns -1 if Γ(x) < 0, +1 if Γ(x) > 0, NAN if sign is indeterminate.

Note that this function can be used in conjunction with logGamma(x) to evaluate gamma for very large values of x.

real beta(real x, real y);
Beta function

The beta function is defined as

beta(x, y) = (Γ(x) * Γ(y)) / Γ(x + y)

real digamma(real x);
Digamma function

The digamma function is the logarithmic derivative of the gamma function.

digamma(x) = d/dx logGamma(x)

real betaIncomplete(real a, real b, real x);
Incomplete beta integral

Returns incomplete beta integral of the arguments, evaluated from zero to x. The regularized incomplete beta function is defined as

betaIncomplete(a, b, x) = Γ(a + b) / ( Γ(a) Γ(b) ) * ∫0x ta-1(1-t)b-1 dt

and is the same as the the cumulative distribution function.

The domain of definition is 0 <= x <= 1. In this implementation a and b are restricted to positive values. The integral from x to 1 may be obtained by the symmetry relation

betaIncompleteCompl(a, b, x ) = betaIncomplete( b, a, 1-x )

The integral is evaluated by a continued fraction expansion or, when b * x is small, by a power series.

real betaIncompleteInverse(real a, real b, real y);
Inverse of incomplete beta integral

Given y, the function finds x such that

betaIncomplete(a, b, x) == y

Newton iterations or interval halving is used.

real gammaIncomplete(real a, real x);
real gammaIncompleteCompl(real a, real x);
Incomplete gamma integral and its complement

These functions are defined by

gammaIncomplete = ( ∫0x e-t ta-1 dt )/ Γ(a)

gammaIncompleteCompl(a,x) = 1 - gammaIncomplete(a,x) = (∫x∞ e-t ta-1 dt )/ Γ(a)

In this implementation both arguments must be positive. The integral is evaluated by either a power series or continued fraction expansion, depending on the relative values of a and x.

real gammaIncompleteComplInverse(real a, real x);
Inverse of complemented incomplete gamma integral

Given a and y, the function finds x such that

gammaIncompleteCompl( a, x ) = p.

real erf(real x);
Error function

The integral is

erf(x) = 2/ √(π) ∫0x exp( - t2) dt

The magnitude of x is limited to about 106.56 for IEEE 80-bit arithmetic; 1 or -1 is returned outside this range.

real erfc(real x);
Complementary error function

erfc(x) = 1 - erf(x) = 2/ √(π) ∫x∞ exp( - t2) dt

This function has high relative accuracy for values of x far from zero. (For values near zero, use erf(x)).

real normalDistribution(real x);
Normal distribution function.

The normal (or Gaussian, or bell-shaped) distribution is defined as:

normalDist(x) = 1/√ π ∫-∞x exp( - t2/2) dt = 0.5 + 0.5 * erf(x/sqrt(2)) = 0.5 * erfc(- x/sqrt(2))

To maintain accuracy at values of x near 1.0, use normalDistribution(x) = 1.0 - normalDistribution(-x).

References:
http://www.netlib.org/cephes/ldoubdoc.html, G. Marsaglia, "Evaluating the Normal Distribution", Journal of Statistical Software 11, (July 2004).

real normalDistributionInverse(real p);
Inverse of Normal distribution function

Returns the argument, x, for which the area under the Normal probability density function (integrated from minus infinity to x) is equal to p.

Based on the CEPHES math library, which is Copyright (C) 1994 Stephen L. Moshier (moshier@world.std.com). | 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

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;

void main(string[] args)
{
    foreach (char[] arg; args)
         MDFile(arg);
}

/* Digests a file and prints the result. */
void MDFile(string filename)
{
    FILE* file = enforce(fopen(filename), "Could not open file `"~filename~"'");
    scope(exit) fclose(file);
    ubyte digest[16];

    MD5_CTX context;
    context.start();
    foreach (ubyte buffer; chunks(file, 4096 * 1024))
        context.update(buffer);
    context.finish(digest);
    writefln("MD5 (%s) = %s", filename, digestToString(digest));
}

void sum(ref ubyte[16u] digest, in void[][] data...);
Computes MD5 digest of several arrays of data.

string digestToString(in ubyte[16u] digest);
Converts MD5 digest to a string.

string getDigestString(in void[][] data...);
Gets the digest of all data items passed in.

Example:
string a = "Mary has ", b = "a little lamb";
int[] c = [ 1, 2, 3, 4, 5 ];
string d = getDigestString(a, b, c);

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(const void[] input);
MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context.

void finish(ref ubyte[16u] digest);
MD5 finalization. Ends an MD5 message-digest operation, writing the the message to digest and zeroing the context.

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.metastrings

Templates with which to do compile-time manipulation of strings.

License:
Boost License 1.0.

Authors:
Walter Bright, Don Clugston

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 toStringNow(ulong v)
template toStringNow(long v)
template toStringNow(uint U)
template toStringNow(int I)
template toStringNow(bool B)
template toStringNow(string S)
template toStringNow(char C)
Convert constant argument to a string.

template parseUinteger(const(char)[] 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(const(char)[] 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

deprecated alias ToString;
deprecated alias ParseUinteger;
deprecated alias ParseInteger;
Deprecated aliases held for backward compatibility.

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


std.mmfile

Read and write memory mapped files.

License:
Boost License 1.0.

Authors:
Walter Bright, Matthew Wilson

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.

Parameters:
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 Digital Mars 2004 - 2009. | Page generated by Ddoc.


std.numeric

This module is a port of a growing fragment of the numeric header in Alexander Stepanov's Standard Template Library, with a few additions.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, Don Clugston, Robert Jacques

enum CustomFloatFlags;
Format flags for CustomFloat.

signed
Adds a sign bit to allow for signed numbers.

storeNormalized
Store values in normalized form by default. The actual precision of the significand is extended by 1 bit by assuming an implicit leading bit of 1 instead of 0. i.e. 1.nnnn instead of 0.nnnn. True for all IEE754 types

allowDenorm
Stores the significand in IEEE754 denormalized form when the exponent is 0. Required to express the value 0.

infinity
Allows the storage of IEEE754 infinity values.

nan
Allows the storage of IEEE754 Not a Number values.

probability
If set, select an exponent bias such that max_exp = 1. i.e. so that the maximum value is >= 1.0 and < 2.0. Ignored if the exponent bias is manually specified.

negativeUnsigned
If set, unsigned custom floats are assumed to be negative.

allowDenormZeroOnly
If set, 0 is the only allowed IEEE754 denormalized number. Requires allowDenorm and storeNormalized.

ieee
Include all of the IEEE754 options.

none
Include none of the above options.

template CustomFloat(uint bits) if (bits == 8 || bits == 16 || bits == 32 || bits == 64 || bits == 80)
template CustomFloat(uint precision,uint exponentWidth,CustomFloatFlags flags = CustomFloatFlags.ieee) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0)
struct CustomFloat(uint precision,uint exponentWidth,CustomFloatFlags flags,uint bias) if (((flags & flags.signed) + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0);
Allows user code to define custom floating-point formats. These formats are for storage only; all operations on them are performed by first implicitly extracting them to real first. After the operation is completed the result can be stored in a custom floating-point value via assignment.

Example:
 // Define a 16-bit floating point values
 CustomFloat!16                                x;     // Using the number of bits
 CustomFloat!(10, 5)                           y;     // Using the precision and exponent width
 CustomFloat!(10, 5,CustomFloatFlags.ieee)     z;     // Using the precision, exponent width and format flags
 CustomFloat!(10, 5,CustomFloatFlags.ieee, 15) w;     // Using the precision, exponent width, format flags and exponent offset bias

 // Use the 16-bit floats mostly like normal numbers
 w = x*y - 1;
 writeln(w);

 // Functions calls require conversion
 z = sin(+x)           + cos(+y);                     // Use uniary plus to concisely convert to a real
 z = sin(x.re)         + cos(y.re);                   // Or use the .re property to convert to a real
 z = sin(x.get!float)  + cos(y.get!float);            // Or use get!T
 z = sin(cast(float)x) + cos(cast(float)y);           // Or use cast(T) to explicitly convert

 // Define a 8-bit custom float for storing probabilities
 alias CustomFloat!(4, 4, CustomFloatFlags.ieee^CustomFloatFlags.probability^CustomFloatFlags.signed ) Probability;
 auto p = Probability(0.5);

template FPTemporary(F) if (isFloatingPoint!(F))
Defines the fastest type to use when storing temporaries of a calculation intended to ultimately yield a result of type F (where F must be one of float, double, or real). When doing a multi-step computation, you may want to store intermediate results as FPTemporary!F.

Example:
// Average numbers in an array
double avg(in double[] a)
{
    if (a.length == 0) return 0;
    FPTemporary!double result = 0;
    foreach (e; a) result += e;
    return result / a.length;
}
The necessity of FPTemporary stems from the optimized floating-point operations and registers present in virtually all processors. When adding numbers in the example above, the addition may in fact be done in real precision internally. In that case, storing the intermediate result in double format is not only less precise, it is also (surprisingly) slower, because a conversion from real to double is performed every pass through the loop. This being a lose-lose situation, FPTemporary!F has been defined as the fastest type to use for calculations at precision F. There is no need to define a type for the most accurate calculations, as that is always real.

Finally, there is no guarantee that using FPTemporary!F will always be fastest, as the speed of floating-point calculations depends on very many factors.

template secantMethod(alias fun)
Implements the secant method for finding a root of the function fun starting from points [xn_1, x_n] (ideally close to the root). Num may be float, double, or real.

Example:
float f(float x) {
    return cos(x) - x*x*x;
}
auto x = secantMethod!(f)(0f, 1f);
assert(approxEqual(x, 0.865474));

T findRoot(T, R)(R delegate(T) f, T a, T b);
Find a real root of a real function f(x) via bracketing.

Given a function f and a range [a..b] such that f(a) and f(b) have opposite signs, returns the value of x in the range which is closest to a root of f(x). If f(x) has more than one root in the range, one will be chosen arbitrarily. If f(x) returns NaN, NaN will be returned; otherwise, this algorithm is guaranteed to succeed.

Uses an algorithm based on TOMS748, which uses inverse cubic interpolation whenever possible, otherwise reverting to parabolic or secant interpolation. Compared to TOMS748, this implementation improves worst-case performance by a factor of more than 100, and typical performance by a factor of 2. For 80-bit reals, most problems require 8 to 15 calls to f(x) to achieve full machine precision. The worst-case performance (pathological cases) is approximately twice the number of bits.

References:
"On Enclosing Simple Roots of Nonlinear Equations", G. Alefeld, F.A. Potra, Yixun Shi, Mathematics of Computation 61, pp733-744 (1993). Fortran code available from www.netlib.org as algorithm TOMS478.

Tuple!(T,T,R,R) findRoot(T, R)(R delegate(T) f, T ax, T bx, R fax, R fbx, bool delegate(T lo, T hi) tolerance);
Find root of a real function f(x) by bracketing, allowing the termination condition to be specified.

Parameters:
f | Function to be analyzed
ax | Left bound of initial range of f known to contain the root.
bx | Right bound of initial range of f known to contain the root.
fax | Value of f(ax).
fbx | Value of f(bx). (f(ax) and f(bx) are commonly known in advance.)
tolerance | Defines an early termination condition. Receives the current upper and lower bounds on the root. The delegate must return true when these bounds are acceptable. If this function always returns false, full machine precision will be achieved.

Returns:
A tuple consisting of two ranges. The first two elements are the range (in x) of the root, while the second pair of elements are the corresponding function values at those points. If an exact root was found, both of the first two elements will contain the root, and the second pair of elements will be 0.

CommonType!(ElementType!(Range1),ElementType!(Range2)) euclideanDistance(Range1, Range2)(Range1 a, Range2 b);
CommonType!(ElementType!(Range1),ElementType!(Range2)) euclideanDistance(Range1, Range2, F)(Range1 a, Range2 b, F limit);
Computes Euclidean distance between input ranges a and b. The two ranges must have the same length. The three-parameter version stops computation as soon as the distance is greater than or equal to limit (this is useful to save computation if a small distance is sought).

CommonType!(ElementType!(Range1),ElementType!(Range2)) dotProduct(Range1, Range2)(Range1 a, Range2 b);
Unqual!(CommonType!(F1,F2)) dotProduct(F1, F2)(in F1[] avector, in F2[] bvector);
Computes the dot product of input ranges a and b. The two ranges must have the same length. If both ranges define length, the check is done once; otherwise, it is done at each iteration.

CommonType!(ElementType!(Range1),ElementType!(Range2)) cosineSimilarity(Range1, Range2)(Range1 a, Range2 b);
Computes the cosine similarity of input ranges a and b. The two ranges must have the same length. If both ranges define length, the check is done once; otherwise, it is done at each iteration. If either range has all-zero elements, return 0.

bool normalize(R)(R range, ElementType!(R) sum = 1);
Normalizes values in range by multiplying each element with a number chosen such that values sum up to sum. If elements in range sum to zero, assigns sum / range.length to all. Normalization makes sense only if all elements in range are positive. normalize assumes that is the case without checking it.

Returns:
true if normalization completed normally, false if all elements in range were zero or if range is empty.

ElementType!(Range) entropy(Range)(Range r);
ElementType!(Range) entropy(Range, F)(Range r, F max);
Computes entropy of input range r in bits. This function assumes (without checking) that the values in r are all in [0, 1]. For the entropy to be meaningful, often r should be normalized too (i.e., its values should sum to 1). The two-parameter version stops evaluating as soon as the intermediate result is greater than or equal to max.

CommonType!(ElementType!(Range1),ElementType!(Range2)) kullbackLeiblerDivergence(Range1, Range2)(Range1 a, Range2 b);
Computes the Kullback-Leibler divergence between input ranges a and b, which is the sum ai * log(ai / bi). The base of logarithm is 2. The ranges are assumed to contain elements in [0, 1]. Usually the ranges are normalized probability distributions, but this is not required or checked by kullbackLeiblerDivergence. If any element bi is zero and the corresponding element ai nonzero, returns infinity. (Otherwise, if ai == 0 && bi == 0, the term ai * log(ai / bi) is considered zero.) If the inputs are normalized, the result is positive.

CommonType!(ElementType!(Range1),ElementType!(Range2)) jensenShannonDivergence(Range1, Range2)(Range1 a, Range2 b);
CommonType!(ElementType!(Range1),ElementType!(Range2)) jensenShannonDivergence(Range1, Range2, F)(Range1 a, Range2 b, F limit);
Computes the Jensen-Shannon divergence between a and b, which is the sum (ai * log(2 * ai / (ai + bi)) + bi * log(2 * bi / (ai + bi))) / 2. The base of logarithm is 2. The ranges are assumed to contain elements in [0, 1]. Usually the ranges are normalized probability distributions, but this is not required or checked by jensenShannonDivergence. If the inputs are normalized, the result is bounded within [0, 1]. The three-parameter version stops evaluations as soon as the intermediate result is greater than or equal to limit.

F gapWeightedSimilarity(alias comp = "a == b", R1, R2, F)(R1 s, R2 t, F lambda);
The so-called "all-lengths gap-weighted string kernel" computes a similarity measure between s and t based on all of their common subsequences of all lengths. Gapped subsequences are also included.

To understand what gapWeightedSimilarity(s, t, lambda) computes, consider first the case lambda = 1 and the strings s = ["Hello", "brave", "new", "world"] and t = ["Hello", "new", "world"]. In that case, gapWeightedSimilarity counts the following matches:

  1. three matches of length 1, namely "Hello", "new", and "world";
  2. three matches of length 2, namely ("Hello", "new"), ("Hello", "world"), and ("new", "world");
  3. one match of length 3, namely ("Hello", "new", "world").

The call gapWeightedSimilarity(s, t, 1) simply counts all of these matches and adds them up, returning 7.

string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
assert(gapWeightedSimilarity(s, t, 1) == 7);
Note how the gaps in matching are simply ignored, for example ("Hello", "new") is deemed as good a match as ("new", "world"). This may be too permissive for some applications. To eliminate gapped matches entirely, use lambda = 0:

string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
assert(gapWeightedSimilarity(s, t, 0) == 4);
The call above eliminated the gapped matches ("Hello", "new"), ("Hello", "world"), and ("Hello", "new", "world") from the tally. That leaves only 4 matches.

The most interesting case is when gapped matches still participate in the result, but not as strongly as ungapped matches. The result will be a smooth, fine-grained similarity measure between the input strings. This is where values of lambda between 0 and 1 enter into play: gapped matches are exponentially penalized with the number of gaps with base lambda. This means that an ungapped match adds 1 to the return value; a match with one gap in either string adds lambda to the return value; ...; a match with a total of n gaps in both strings adds pow(lambda, n) to the return value. In the example above, we have 4 matches without gaps, 2 matches with one gap, and 1 match with three gaps. The latter match is ("Hello", "world"), which has two gaps in the first string and one gap in the second string, totaling to three gaps. Summing these up we get 4 + 2 * lambda + pow(lambda, 3).

string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
assert(gapWeightedSimilarity(s, t, 0.5) == 4 + 0.5 * 2 + 0.125);
gapWeightedSimilarity is useful wherever a smooth similarity measure between sequences allowing for approximate matches is needed. The examples above are given with words, but any sequences with elements comparable for equality are allowed, e.g. characters or numbers. gapWeightedSimilarity uses a highly optimized dynamic programming implementation that needs 16 * min(s.length, t.length) extra bytes of memory and Ο(s.length * t.length) time to complete.

Select!(isFloatingPoint!(F),F,double) gapWeightedSimilarityNormalized(alias comp = "a == b", R1, R2, F)(R1 s, R2 t, F lambda, F sSelfSim = F.init, F tSelfSim = F.init);
The similarity per gapWeightedSimilarity has an issue in that it grows with the lengths of the two strings, even though the strings are not actually very similar. For example, the range ["Hello", "world"] is increasingly similar with the range ["Hello", "world", "world", "world",...] as more instances of "world" are appended. To prevent that, gapWeightedSimilarityNormalized computes a normalized version of the similarity that is computed as gapWeightedSimilarity(s, t, lambda) / sqrt(gapWeightedSimilarity(s, t, lambda) * gapWeightedSimilarity(s, t, lambda)). The function gapWeightedSimilarityNormalized (a so-called normalized kernel) is bounded in [0, 1], reaches 0 only for ranges that don't match in any position, and 1 only for identical ranges.

Example:
string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
assert(gapWeightedSimilarity(s, s, 1) == 15);
assert(gapWeightedSimilarity(t, t, 1) == 7);
assert(gapWeightedSimilarity(s, t, 1) == 7);
assert(gapWeightedSimilarityNormalized(s, t, 1) == 7. / sqrt(15. * 7));
The optional parameters sSelfSim and tSelfSim are meant for avoiding duplicate computation. Many applications may have already computed gapWeightedSimilarity(s, s, lambda) and/or gapWeightedSimilarity(t, t, lambda). In that case, they can be passed as sSelfSim and tSelfSim, respectively.

struct GapWeightedSimilarityIncremental(Range,F = double) if (isRandomAccessRange!(Range) && hasLength!(Range));
GapWeightedSimilarityIncremental!(R,F) gapWeightedSimilarityIncremental(R, F)(R r1, R r2, F penalty);
Similar to gapWeightedSimilarity, just works in an incremental manner by first revealing the matches of length 1, then gapped matches of length 2, and so on. The memory requirement is Ο(s.length * t.length). The time complexity is Ο(s.length * t.length) time for computing each step. Continuing on the previous example:

string[] s = ["Hello", "brave", "new", "world"];
string[] t = ["Hello", "new", "world"];
auto simIter = gapWeightedSimilarityIncremental(s, t, 1);
assert(simIter.front == 3); // three 1-length matches
simIter.popFront;
assert(simIter.front == 3); // three 2-length matches
simIter.popFront;
assert(simIter.front == 1); // one 3-length match
simIter.popFront;
assert(simIter.empty);     // no more match
The implementation is based on the pseudocode in Fig. 4 of the paper "Efﬁcient Computation of Gapped Substring Kernels on Large Alphabets" by Rousu et al., with additional algorithmic and systems-level optimizations.

__ctor;
Constructs an object given two ranges s and t and a penalty lambda. Constructor completes in Ο(s.length * t.length) time and computes all matches of length 1.

GapWeightedSimilarityIncremental opSlice();
Returns this.

void popFront();
Computes the match of the popFront length. Completes in Ο(s.length * t.length) time.

F front();
Returns the gapped similarity at the current match length (initially 1, grows with each call to popFront).

bool empty();
Returns whether there are more matches.

T gcd(T)(T a, T b);
Computes the greatest common divisor of a and b by using Euler's algorithm.

class Fft;
A class for performing fast Fourier transforms of power of two sizes. This class encapsulates a large amount of state that is reusable when performing multiple FFTs of the same size. This makes performing numerous FFTs of the same size faster than a free function API would allow. However, a free function API is provided for convenience if you need to perform a one-off FFT.

References:
en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm

this(size_t size);
Create an Fft object for computing fast Fourier transforms of the provided size. size must be a power of two.

Complex!(F)[] fft(F = double, R)(R range);
Compute the Fourier transform of range using the Ο(N log N) Cooley-Tukey Algorithm. range must be a random-access range with slicing and a length equal to size as provided at the construction of this object. The contents of range can be either numeric types, which will be interpreted as pure real values, or complex types with properties or members .re and .im that can be read.

Returns:
An array of complex numbers representing the transformed data in the frequency domain.

void fft(Ret, R)(R range, Ret buf);
Same as the overload, but allows for the results to be stored in a user- provided buffer. The buffer must be of the same length as range, must be a random-access range, must have slicing, and must contain elements that are complex-like. This means that they must have a .re and a .im member or property that can be both read and written and are floating point numbers.

Complex!(F)[] inverseFft(F = double, R)(R range);
Computes the inverse Fourier transform of a range. The range must be a random access range with slicing, have a length equal to the size provided at construction of this object, and contain elements that are either of type std.complex.Complex or have essentially the same compile-time interface.

Returns:
The time-domain signal.

void inverseFft(Ret, R)(R range, Ret buf);
Inverse FFT that allows a user-supplied buffer to be provided. The buffer must be a random access range with slicing, and its elements must be some complex-like type.

Complex!(F)[] fft(F = double, R)(R range);
void fft(Ret, R)(R range, Ret buf);
Complex!(F)[] inverseFft(F = double, R)(R range);
void inverseFft(Ret, R)(R range, Ret buf);
Convenience functions that create an Fft object, run the FFT or inverse FFT and return the result. Useful for one-off FFTs.

Note:
In addition to convenience, these functions are slightly more efficient than manually creating an Fft object for a single use, as the Fft object is deterministically destroyed before these functions return.

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


std.outbuffer

Boilerplate:

License:
Boost License 1.0.

Authors:
Walter Bright

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(const(ubyte)[] bytes);
void write(ubyte b);
void write(byte b);
void write(char c);
void write(dchar 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(in char[] s);
void write(OutBuffer buf);
Append data to the internal buffer.

void fill0(uint nbytes);
Append nbytes of 0 to the internal buffer.

void alignSize(uint 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 Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.outofmemory

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

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()).

License:
Boost License 1.0.

Authors:
Walter Bright, Grzegorz Adam Hankiewicz, Thomas Kühne, Bill Baxter, Andrei Alexandrescu

string sep;
String used to separate directory names in a path. Under Windows this is a backslash, under Linux a slash.

string altsep;
Alternate version of sep[] used in Windows (a slash). Under Linux this is empty.

string pathsep;
Path separator string. A semi colon under Windows, a colon under Linux.

string linesep;
String used to separate lines, \r\n under Windows and \n under Linux. String used to separate lines.

string curdir;
String representing the current directory.

string 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") => "d:\path"
     getName("/home/user/.resource") => "/home/user/"
 }

Char[] basename(Char, ExtChar = immutable(char))(Char[] fullname, ExtChar[] extension = null);
Extracts the base name of a path and optionally chops off a specific suffix.

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. After the search has ended, keep the portion to the right of the separator if found, or the entire fullname otherwise. If the kept portion has suffix extension, remove that suffix. Return the remaining string.

Returns:
The portion of fullname left after the path part and the extension part, if any, have been removed.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     basename(r"d:\path\foo.bat") => "foo.bat"
     basename(r"d:\path\foo", ".bat") => "foo"
 }
 version(Posix)
 {
     basename("/home/user.name/bar.")  => "bar."
     basename("/home/user.name/bar.", ".")  => "bar"
 }

alias getBaseName;
Alias for basename, kept for backward compatibility. New code should use basename.

Char[] dirname(Char)(Char[] 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 without any trailing path separators are returned. Otherwise, "." is returned.

The found path separator will be included in the returned string if and only if it represents the root.

Throws:
Nothing.

Examples:
 version(Windows)
 {
     assert(dirname(r"d:\path\foo.bat") == r"d:\path");
     assert(dirname(r"d:\path") == r"d:\");
     assert(dirname("d:foo.bat") == "d:.");
     assert(dirname("foo.bat") == ".");
 }
 version(Posix)
 {
     assert(dirname("/home/user") == "/home");
     assert(dirname("/home") == "/");
     assert(dirname("user") == ".");
 }

alias getDirName;
Alias for dirname, kept for backward compatibility. New code should use dirname.

Char[] getDrive(Char)(Char[] 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"

bool isabs(in char[] 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 rel2abs(string path);
Converts a relative path into an absolute path.

string join(const(char)[] p1, const(char)[] p2, const(char)[][] more...);
Joins two or more path components.

If p1 doesn't have a trailing path separator, one will be appended to it before concatenating 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"
 }

bool 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
 }

bool fnmatch(const(char)[] filename, const(char)[] 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;

 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.

Copyright Digital Mars 2000-. | Page generated by Ddoc.


std.process

Authors:
Walter Bright, Andrei Alexandrescu

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

int system(string command);
Execute command in a command shell.

Returns:
If command is null, returns nonzero if the command interpreter is found, and zero otherwise. If command is not null, returns -1 on error, or the exit status of command (which may in turn signal an error in command's execution).

Note:
On Unix systems, the homonym C function (which is accessible to D programs as std.c.system) returns a code in the same format as waitpid, meaning that C programs must use the WEXITSTATUS macro to extract the actual exit code from the system call. D's system automatically extracts the exit status.

int execv(in string pathname, in string[] argv);
int execve(in string pathname, in string[] argv, in string[] envp);
int execvp(in string pathname, in string[] argv);
int execvpe(in string pathname, in string[] argv, in 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.

string shell(string cmd);
Runs cmd in a shell and returns its standard output. If the process could not be started or exits with an error code, throws an exception.

Example:
   auto tempFilename = chomp(shell("mcookie"));
   auto f = enforce(fopen(tempFilename), "w");
   scope(exit)
   {
       fclose(f) == 0 || assert(false);
       system("rm " ~ tempFilename);
   }
   ... use f ...

string getenv(in char[] name);
Gets the value of environment variable name as a string. Calls std.c.stdlib.getenv internally.

alias environment;
Manipulates environment variables using an associative-array-like interface.

Examples:
    // Return variable, or throw an exception if it doesn't exist.
    auto path = environment["PATH"];

    // Add/replace variable.
    environment["foo"] = "bar";

    // Remove variable.
    environment.remove("foo");

    // Return variable, or null if it doesn't exist.
    auto foo = environment.get("foo");

    // Return variable, or a default value if it doesn't exist.
    auto foo = environment.get("foo", "default foo value");

    // Return an associative array of type string[string] containing
    // all the environment variables.
    auto aa = environment.toAA();

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


std.random

Facilities for random number generation. The old-style functions rand_seed and rand will soon be deprecated as they rely on global state and as such are subjected to various thread-related issues.

The new-style generator objects hold their own state so they are immune of threading issues. The generators feature a number of well-known and well-documented methods of generating random numbers. An overall fast and reliable means to generate random numbers is the Mt19937 generator, which derives its name from "Mersenne Twister with a period of 2 to the power of 19937". In memory-constrained situations, linear congruential generators such as MinstdRand0 and MinstdRand might be useful. The standard library provides an alias Random for whichever generator it considers the most fit for the target environment.

Example:
// Generate a uniformly-distributed integer in the range [0, 14]
auto i = uniform(0, 15);
// Generate a uniformly-distributed real in the range [0, 100)
// using a specific random generator
Random gen;
auto r = uniform(0.0L, 100.0L, gen);
In addition to random number generators, this module features distributions, which skew a generator's output statistical distribution in various ways. So far the uniform distribution for integers and real numbers have been implemented.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

Credits:
The entire random number library architecture is derived from the excellent C++0X random number facility proposed by Jens Maurer and contributed to by researchers at the Fermi laboratory.

struct LinearCongruentialEngine(UIntType,UIntType a,UIntType c,UIntType m);
Linear Congruential generator.

bool hasFixedRange;
Does this generator have a fixed range? (true).

UIntType min;
Lowest generated value (1 if c == 0, 0 otherwise).

UIntType max;
Highest generated value (modulus - 1).

UIntType multiplier;
UIntType increment;
UIntType modulus;
The parameters of this distribution. The random number is x = (x * multipler + increment) % modulus.

__ctor;
Constructs a LinearCongruentialEngine generator seeded with x0.

void seed(UIntType x0 = 1);
(Re)seeds the generator.

void popFront();
Advances the random sequence.

UIntType front();
Returns the current number in the random sequence.

typeof(this) save();

bool empty;
Always false (random generators are infinite ranges).

const bool opEquals(ref const LinearCongruentialEngine rhs);
Compares against rhs for equality.

alias MinstdRand0;
alias MinstdRand;
Define LinearCongruentialEngine generators with well-chosen parameters. MinstdRand0 implements Park and Miller's "minimal standard" generator that uses 16807 for the multiplier. MinstdRand implements a variant that has slightly better spectral behavior by using the multiplier 48271. Both generators are rather simplistic.

Example:
// seed with a constant
auto rnd0 = MinstdRand0(1);
auto n = rnd0.front; // same for each run
// Seed with an unpredictable value
rnd0.seed(unpredictableSeed);
n = rnd0.front; // different across runs

struct MersenneTwisterEngine(UIntType,size_t w,size_t n,size_t m,size_t r,UIntType a,size_t u,size_t s,UIntType b,size_t t,UIntType c,size_t l);
The Mersenne Twister generator.

size_t wordSize;
Parameter for the generator.

UIntType min;
Smallest generated value (0).

UIntType max;
Largest generated value.

UIntType defaultSeed;
The default seed value.

__ctor;
Constructs a MersenneTwisterEngine object.

void seed(UIntType value = defaultSeed);
Seeds a MersenneTwisterEngine object.

void popFront();
Advances the generator.

UIntType front();
Returns the current random value.

typeof(this) save();

bool empty;
Always false.

alias Mt19937;
A MersenneTwisterEngine instantiated with the parameters of the original engine MT19937, generating uniformly-distributed 32-bit numbers with a period of 2 to the power of 19937. Recommended for random number generation unless memory is severely restricted, in which case a LinearCongruentialEngine would be the generator of choice.

Example:
// seed with a constant
Mt19937 gen;
auto n = gen.front; // same for each run
// Seed with an unpredictable value
gen.seed(unpredictableSeed);
n = gen.front; // different across runs

uint unpredictableSeed();
A "good" seed for initializing random number engines. Initializing with unpredictableSeed makes engines generate different random number sequences every run.

Example:
auto rnd = Random(unpredictableSeed);
auto n = rnd.front;
...

alias Random;
The "default", "favorite", "suggested" random number generator type on the current platform. It is an alias for one of the previously-defined generators. You may want to use it if (1) you need to generate some nice random numbers, and (2) you don't care for the minutiae of the method being used.

Random rndGen();
Global random number generator used by various functions in this module whenever no generator is specified. It is allocated per-thread and initialized to an unpredictable value for each thread.

CommonType!(T1,T2) uniform(string boundaries = "[)", T1, T2, UniformRandomNumberGenerator
(T1 a, T2 b, ref UniformRandomNumberGenerator urng);
Generates a number between a and b. The boundaries parameter controls the shape of the interval (open vs. closed on either side). Valid values for boundaries are "[]", "(]", "[)", and "()". The default interval is closed to the left and open to the right.

Example:
Random gen(unpredictableSeed);
// Generate an integer in [0, 1023]
auto a = uniform(0, 1024, gen);
// Generate a float in [0, 1)
auto a = uniform(0.0f, 1.0f, gen);

CommonType!(T1,T2) uniform(string boundaries = "[)", T1, T2
(T1 a, T2 b); )
As above, but uses the default generator rndGen.

F[] uniformDistribution(F = double)(size_t n, F[] useThis = null);
Generates a uniform probability distribution of size n, i.e., an array of size n of positive numbers of type F that sum to 1. If useThis is provided, it is used as storage.

void randomShuffle(Range, RandomGen = Random)(Range r, ref RandomGen gen = rndGen);
Shuffles elements of r using r as a shuffler. r must be a random-access range with length.

size_t dice(R, Num)(ref R rnd, Num[] proportions...);
size_t dice(R, Range)(ref R rnd, Range proportions);
size_t dice(Num)(Num[] proportions...);
size_t dice(Range)(Range proportions);
Rolls a dice with relative probabilities stored in proportions. Returns the index in proportions that was chosen.

Example:
auto x = dice(0.5, 0.5);   // x is 0 or 1 in equal proportions
auto y = dice(50, 50);     // y is 0 or 1 in equal proportions
auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 30% of the time,
                           // and 2 10% of the time

struct RandomCover(Range,Random);
RandomCover!(Range,Random) randomCover(Range, Random)(Range r, Random rnd);
Covers a given range r in a random manner, i.e. goes through each element of r once and only once, just in a random order. r must be a random-access range with length.

Example:
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ];
auto rnd = Random(unpredictableSeed);
foreach (e; randomCover(a, rnd))
{
    writeln(e);
}

struct RandomSample(R);
RandomSample!(R) randomSample(R)(R r, size_t n, size_t total);
RandomSample!(R) randomSample(R)(R r, size_t n);
Selects a random subsample out of r, containing exactly n elements. The order of elements is the same as in the original range. The total length of r must be known. If total is passed in, the total number of sample is considered to be total. Otherwise, RandomSample uses r.length.

If the number of elements is not exactly total, RandomSample throws an exception. This is because total is essential to computing the probability of selecting elements in the range.

Example:
int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
// Print 5 random elements picked off from r
foreach (e; randomSample(n, 5))
{
    writeln(e);
}

__ctor;
__ctor;
Constructor.

const bool empty();
void popFront();
typeof(this) save();
size_t length();
Range primitives.

size_t index();
Returns the index of the visited record.

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.

BUGS:
Shares a global single state, not multithreaded. SCHEDULED FOR DEPRECATION.

deprecated uint rand();
Get the popFront random number in sequence.

BUGS:
Shares a global single state, not multithreaded. SCHEDULED FOR DEPRECATION.

)

Copyright Andrei Alexandrescu 2008 - 2009. | Page generated by Ddoc.


std.range

This module defines a few useful range incarnations. Credit for some of the ideas in building this module goes to Leonardo Maffi.

Source:
std/range.d

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, David Simcha

template isInputRange(R)
Returns true if R is an input range. An input range must define the primitives empty, popFront, and front. The following code should compile for any input range.

R r;             // can define a range object
if (r.empty) {}  // can test for empty
r.popFront;          // can invoke next
auto h = r.front; // can get the front of the range
The semantics of an input range (not checkable during compilation) are assumed to be the following (r is an object of type R):

  • r.empty returns false iff there is more data available in the range.
  • r.front returns the current element in the range. It may return by value or by reference. Calling r.front is allowed only if calling r.empty has, or would have, returned false.
  • r.popFront advances to the popFront element in the range. Calling r.popFront is allowed only if calling r.empty has, or would have, returned false.

void put(R, E)(ref R r, E e);
Outputs e to r. The exact effect is dependent upon the two types. which must be an output range. Several cases are accepted, as described below. The code snippets are attempted in order, and the first to compile "wins" and gets evaluated.

Code Snippet | Scenario
r.put(e); | R specifically defines a method put accepting an E.
r.put([ e ]); | R specifically defines a method put accepting an E[].
r.front = e; r.popFront(); | R is an input range and e is assignable to r.front.
for (; !e.empty; e.popFront()) put(r, e.front); | Copying range E to range R.
r(e); | R is e.g. a delegate accepting an E.
r([ e ]); | R is e.g. a delegate accepting an E[].

template isOutputRange(R,E)
Returns true if R is an output range for elements of type E. An output range can be defined functionally as a range that supports the operation put(r, e) as defined above.

template isForwardRange(R)
Returns true if R is a forward range. A forward range is an input range that can save "checkpoints" by simply copying it to another value of the same type. Notable examples of input ranges that are not forward ranges are file/socket ranges; copying such a range will not save the position in the stream, and they most likely reuse an internal buffer as the entire stream does not sit in memory. Subsequently, advancing either the original or the copy will advance the stream, so the copies are not independent. The following code should compile for any forward range.

static assert(isInputRange!(R));
R r1;
R r2 = r1;           // can copy a range to another
The semantics of a forward range (not checkable during compilation) are the same as for an input range, with the additional requirement that backtracking must be possible by saving a copy of the range object.

template isBidirectionalRange(R)
Returns true if R is a bidirectional range. A bidirectional range is a forward range that also offers the primitives back and popBack. The following code should compile for any bidirectional range.

R r;
static assert(isForwardRange!(R)); // range is an input range
r.popBack;                        // can invoke popBack
auto t = r.back;                   // can get the back of the range
The semantics of a bidirectional range (not checkable during compilation) are assumed to be the following (r is an object of type R):

  • r.back returns (possibly a reference to) the last element in the range. Calling r.back is allowed only if calling r.empty has, or would have, returned false.

template isRandomAccessRange(R)
Returns true if R is a random-access range. A random-access range is a bidirectional range that also offers the primitive opIndex, OR an infinite forward range that offers opIndex. In either case, the range must either offer length or be infinite. The following code should compile for any random-access range.

R r;
static assert(isForwardRange!(R)); // range is forward
static assert(isBidirectionalRange!(R) || isInfinite!(R));
                                  // range is bidirectional or infinite
auto e = r[1];                    // can index
The semantics of a random-access range (not checkable during compilation) are assumed to be the following (r is an object of type R):
  • r.opIndex(n) returns a reference to the nth element in the range.

template hasMobileElements(R)
Returns true iff the range supports the moveFront primitive, as well as moveBack and moveAt if it's a bidirectional or random access range. These may be explicitly implemented, or may work via the default behavior of the module level functions moveFront and friends.

template ElementType(R)
The element type of R. R does not have to be a range. The element type is determined as the type yielded by r.front for an object r or type R. For example, ElementType!(T[]) is T.

template hasSwappableElements(R)
Returns true if R is a forward range and has swappable elements. The following code should compile for any random-access range.

R r;
static assert(isForwardRange!(R));  // range is forward
swap(r.front, r.front);              // can swap elements of the range

template hasAssignableElements(R)
Returns true if R is a forward range and has mutable elements. The following code should compile for any random-access range.

R r;
static assert(isForwardRange!(R));  // range is forward
auto e = r.front;
r.front = e;                         // can assign elements of the range

template hasLvalueElements(R)
Tests whether R has lvalue elements. These are defined as elements that can be passed by reference and have their address taken.

template hasLength(R)
Returns true if R has a length member that returns an integral type. R does not have to be a range. Note that length is an optional primitive as no range must implement it. Some ranges do not store their length explicitly, some cannot compute it without actually exhausting the range (e.g. socket streams), and some other ranges may be infinite.

template isInfinite(Range)
Returns true if Range is an infinite input range. An infinite input range is an input range that has a statically-defined enumerated member called empty that is always false, for

example:
struct InfiniteRange
{
    enum bool empty = false;
    ...
}

template hasSlicing(Range)
Returns true if Range offers a slicing operator with integral boundaries, that in turn returns an input range type. The following code should compile for hasSlicing to be true:

Range r;
auto s = r[1 .. 2];
static assert(isInputRange!(typeof(s)));

size_t walkLength(Range)(Range range, size_t upTo = size_t.max);
This is a best-effort implementation of length for any kind of range.

If hasLength!(Range), simply returns range.length without checking upTo.

Otherwise, walks the range through its length and returns the number of elements seen. Performes Ο(n) evaluations of range.empty and range.popFront, where n is the effective length of range. The upTo parameter is useful to "cut the losses" in case the interest is in seeing whether the range has at least some number of elements. If the parameter upTo is specified, stops if upTo steps have been taken and returns upTo.

struct Retro(Range) if (isBidirectionalRange!(Unqual!(Range)) && !isRetro!(Range));
Retro!(R) retro(R)(R input);
Iterates a bidirectional range backwards.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
assert(equal(retro(a), [ 5, 4, 3, 2, 1 ][]));

bool empty();
Forwards to input.empty.

Retro save();
Returns a copy of this.

void popFront();
Forwards to input.popBack.

ElementType!(R) moveFront();
Forwards to moveBack(input)

void popBack();
Forwards to input.popFront.

ElementType!(R) moveBack();
Forwards to moveFront(input).

front(ElementType!(R) val);
Support for assignment.

back(ElementType!(R) val);
Support for assignment.

opIndex(size_t n);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

void opIndexAssign(ElementType!(R) val, size_t n);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

ElementType!(R) moveAt(size_t index);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

typeof(this) opSlice(size_t a, size_t b);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

size_t length();
Range primitive operation that returns the length of the range. Forwards to input.length and is defined only if hasLength!(R).

struct Stride(Range) if (isInputRange!(Unqual!(Range)));
Stride!(R) stride(R)(R input, size_t n);
Iterates range r with stride n. If the range is a random-access range, moves by indexing into the range; otehrwise, moves by successive calls to popFront.

Example:
int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][]));

__ctor;
Initializes the stride.

Stride save();
Returns this.

bool empty;
Forwards to input.empty.

ElementType!(R) moveFront();
Forwards to moveFront(input).

void popFront();
@@@

void popBack();
Forwards to input.popBack.

back();
Forwards to input.back after getting rid of any slack items.

ElementType!(R) moveBack();
Forwards to moveBack(input).

Forwards to input.back after getting rid of any slack items.

back(ElementType!(R) val);
Forwards to input.back after getting rid of any slack items.

opIndex(size_t n);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

ElementType!(R) moveAt(size_t n);
Forwards to moveAt(input, n).

Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

void opIndexAssign(ElementType!(R) val, size_t n);
Forwards to input[input.length - n + 1]. Defined only if R is a random access range and if R defines R.length.

typeof(this) opSlice(size_t lower, size_t upper);
Support slicing of the Stride, if the underlying range supports this.

size_t length();
Range primitive operation that returns the length of the range. Forwards to input.length and is defined only if hasLength!(R).

template Chain(R...) if (allSatisfy!(isInputRange,staticMap!(Unqual,R)))
Chain!(R) chain(R...)(R input);
Spans multiple ranges in sequence. The function chain takes any number of ranges and returns a Chain!(R1, R2,...) object. The ranges may be different, but they must have the same element type. The result is a range that offers the front, popFront, and empty primitives. If all input ranges offer random access and length, Chain offers them as well.

If only one range is offered to Chain or chain, the Chain type exits the picture by aliasing itself directly to that range's type.

Example:
int[] arr1 = [ 1, 2, 3, 4 ];
int[] arr2 = [ 5, 6 ];
int[] arr3 = [ 7 ];
auto s = chain(arr1, arr2, arr3);
assert(s.length == 7);
assert(s[5] == 6);
assert(equal(s, [1, 2, 3, 4, 5, 6, 7][]));

struct Radial(Range) if (isRandomAccessRange!(Unqual!(Range)) && hasLength!(Unqual!(Range)));
Radial!(R) radial(R)(R r);
Radial!(R) radial(R)(R r, size_t startingIndex);
Iterates a random-access range starting from a given point and progressively extending left and right from that point. If no initial point is given, iteration starts from the middle of the range. Iteration spans the entire range.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
assert(equal(radial(a), [ 3, 4, 2, 5, 1 ][]));
a = [ 1, 2, 3, 4 ];
assert(equal(radial(a), [ 2, 3, 1, 4 ][]));

__ctor;
Takes a range and starts iterating from its median point. Ranges with an even length start iterating from the element to the left of the median. The second iterated element, if any, is the one to the right of the first iterated element. A convenient way to use this constructor is by calling the helper function radial(input).

__ctor;
Takes a range and starts iterating from input[mid]. The second iterated element, if any, is the one to the right of the first iterated element. If there is no element to the right of input[mid], iteration continues downwards with input[mid - 1] etc. A convenient way to use this constructor is by calling the helper function radial(input, startingPoint).

Radial opSlice();
Returns this.

bool empty();
Range primitive operation that returns true iff there are no more elements to be iterated.

void popFront();
Range primitive operation that advances the range to its next element.

ElementType!(R) moveFront();

front(ElementType!(R) val);

typeof(this) save();

struct Take(Range) if (isInputRange!(Unqual!(Range)) && (!hasSlicing!(Unqual!(Range)) || isNarrowString!(Unqual!(Range))));
R take(R)(R input, size_t n);
Take!(R) take(R)(R input, size_t n);
Take!(R) take(R)(R input, size_t n);
Lazily takes only up to n elements of a range. This is particulary useful when using with infinite ranges. If the range offers random access and length, Take offers them as well.

Example:
int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
auto s = take(arr1, 5);
assert(s.length == 5);
assert(s[4] == 5);
assert(equal(s, [ 1, 2, 3, 4, 5 ][]));

size_t popFrontN(Range)(ref Range r, size_t n);
Eagerly advances r itself (not a copy) n times (by calling r.popFront n times). The pass of r into popFrontN is by reference, so the original range is affected. Completes in Ο(1) steps for ranges that support slicing, and in Ο(n) time for all other ranges.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popFrontN(2);
assert(a == [ 3, 4, 5 ]);

size_t popBackN(Range)(ref Range r, size_t n);
Eagerly reduces r itself (not a copy) n times from its right side (by calling r.popBack n times). The pass of r into popBackN is by reference, so the original range is affected. Completes in Ο(1) steps for ranges that support slicing, and in Ο(n) time for all other ranges.

Example:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popBackN(2);
assert(a == [ 1, 2, 3 ]);

struct Repeat(T);
Repeat!(T) repeat(T)(T value);
Repeats one value forever. Example:
enforce(equal(take(repeat(5), 4), [ 5, 5, 5, 5 ][]));

T front();
T back();
bool empty;
void popFront();
void popBack();
Repeat!(T) save();
T opIndex(size_t);
Range primitive implementations.

Take!(Repeat!(T)) replicate(T)(T value, size_t n);
Replicates value exactly n times. Equivalent to take(repeat(value), n).

struct Cycle(Range) if (isForwardRange!(Unqual!(Range)) && !isInfinite!(Unqual!(Range)));
template Cycle(R) if (isInfinite!(R))
struct Cycle(R) if (isStaticArray!(R));
Cycle!(R) cycle(R)(R input);
Cycle!(R) cycle(R)(R input, size_t index);
Cycle!(R) cycle(R)(R input);
Cycle!(R) cycle(R)(ref R input, size_t index = 0);
Repeats the given forward range ad infinitum. If the original range is infinite (fact that would make Cycle the identity application), Cycle detects that and aliases itself to the range type itself. If the original range has random access, Cycle offers random access and also offers a constructor taking an initial position index. Cycle is specialized for statically-sized arrays, mostly for performance reasons.

Example:
assert(equal(take(cycle([1, 2][]), 5), [ 1, 2, 1, 2, 1 ][]));

Tip:
This is a great way to implement simple circular buffers.

front(ElementType!(R) val);
bool empty;
void popFront();
opIndexAssign(ElementType!(R) val, size_t n);
Cycle!(R) save();
Ditto

struct Zip(Ranges...) if (Ranges.length && allSatisfy!(isInputRange,staticMap!(Unqual,Ranges)));
Zip!(R) zip(R...)(R ranges);
Zip!(R) zip(R...)(StoppingPolicy sp, R ranges);
Iterate several ranges in lockstep. The element type is a proxy tuple that allows accessing the current element in the nth range by using e[n].

Example:
int[] a = [ 1, 2, 3 ];
string[] b = [ "a", "b", "c" ];
// prints 1:a 2:b 3:c
foreach (e; zip(a, b))
{
    write(e[0], ':', e[1], ' ');
}
Zip offers the lowest range facilities of all components, e.g. it offers random access iff all ranges offer random access, and also offers mutation and swapping if all ranges offer it. Due to this, Zip is extremely powerful because it allows manipulating several ranges in lockstep. For example, the following code sorts two arrays in parallel:

int[] a = [ 1, 2, 3 ];
string[] b = [ "a", "b", "c" ];
sort!("a[0] > b[0]")(zip(a, b));
assert(a == [ 3, 2, 1 ]);
assert(b == [ "c", "b", "a" ]);

__ctor;
Builds an object. Usually this is invoked indirectly by using the std.range.zip function.

bool empty;
Returns true if the range is at end. The test depends on the stopping policy.

ElementType front();
Returns the current iterated element.

void front(ElementType v);
Sets the front of all iterated ranges.

ElementType moveFront();
Moves out the front.

ElementType back();
Returns the rightmost element.

ElementType moveBack();
Moves out the back.

Returns the rightmost element.

void back(ElementType v);
Returns the current iterated element.

Returns the rightmost element.

void popFront();
Advances to the popFront element in all controlled ranges.

void popBack();
Calls popBack for all controlled ranges.

size_t length();
Returns the length of this range. Defined only if all ranges define length.

Zip opSlice(size_t from, size_t to);
Returns a slice of the range. Defined only if all range define slicing.

ElementType opIndex(size_t n);
Returns the nth element in the composite range. Defined if all ranges offer random access.

void opIndexAssign(ElementType v, size_t n);
Assigns to the nth element in the composite range. Defined if all ranges offer random access.

ElementType moveAt(size_t n);
Destructively reads the nth element in the composite range. Defined if all ranges offer random access.

enum StoppingPolicy;
Dictates how iteration in a Zip should stop. By default stop at the end of the shortest of all ranges.

shortest
Stop when the shortest range is exhausted

longest
Stop when the longest range is exhausted

requireSameLength
Require that all ranges are equal

struct Lockstep(Ranges...) if (Ranges.length > 1 && allSatisfy!(isInputRange,staticMap!(Unqual,Ranges)));
Iterate multiple ranges in lockstep using a foreach loop. If only a single range is passed in, the Lockstep aliases itself away. If the ranges are of different lengths and s == StoppingPolicy.shortest stop after the shortest range is empty. If the ranges are of different lengths and s == StoppingPolicy.requireSameLength, throw an exception. s may not be StoppingPolicy.longest, and passing this will throw an exception.

BUGS:
If a range does not offer lvalue access, but ref is used in the foreach loop, it will be silently accepted but any modifications to the variable will not be propagated to the underlying range.

Examples:
auto arr1 = [1,2,3,4,5];
auto arr2 = [6,7,8,9,10];

foreach(ref a, ref b; lockstep(arr1, arr2))
{
   a += b;
}

assert(arr1 == [7,9,11,13,15]);

// Lockstep also supports iterating with an index variable:
foreach(index, a, b; lockstep(arr1, arr2)) {
    writefln("Index %s:  a = %s, b = %s", index, a, b);
}

struct Recurrence(alias fun,StateType,size_t stateSize);
Recurrence!(fun,CommonType!(State),State.length) recurrence(alias fun, State...)(State initial);
Creates a mathematical sequence given the initial values and a recurrence function that computes the popFront value from the existing values. The sequence comes in the form of an infinite forward range. The type Recurrence itself is seldom used directly; most often, recurrences are obtained by calling the function recurrence.

When calling recurrence, the function that computes the next value is specified as a template argument, and the initial values in the recurrence are passed as regular arguments. For example, in a Fibonacci sequence, there are two initial values (and therefore a state size of 2) because computing the popFront Fibonacci value needs the past two values.

If the function is passed in string form, the state has name "a" and the zero-based index in the recurrence has name "n". The given string must return the desired value for a[n] given a[n - 1], a[n - 2], a[n - 3],..., a[n - stateSize]. The state size is dictated by the number of arguments passed to the call to recurrence. The Recurrence class itself takes care of managing the recurrence's state and shifting it appropriately.

Example:
// a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n]
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
// print the first 10 Fibonacci numbers
foreach (e; take(fib, 10)) { writeln(e); }
// print the first 10 factorials
foreach (e; take(recurrence!("a[n-1] * n")(1), 10)) { writeln(e); }

struct Sequence(alias fun,State);
Sequence!(fun,Tuple!(State)) sequence(alias fun, State...)(State args);
Sequence is similar to Recurrence except that iteration is presented in the so-called closed form. This means that the nth element in the series is computable directly from the initial values and n itself. This implies that the interface offered by Sequence is a random-access range, as opposed to the regular Recurrence, which only offers forward iteration.

The state of the sequence is stored as a Tuple so it can be heterogeneous.

Example:
// a[0] = 1, a[1] = 2, a[n] = a[0] + n * a[1]
auto odds = sequence!("a[0] + n * a[1]")(1, 2);

Iota!(CommonType!(Unqual!(B),Unqual!(E)),S) iota(B, E, S)(B begin, E end, S step);
Iota!(CommonType!(Unqual!(B),Unqual!(E)),uint) iota(B, E)(B begin, E end);
Iota!(Unqual!(E),uint) iota(E)(E end);
struct Iota(N,S) if ((isIntegral!(N) || isPointer!(N)) && isIntegral!(S));
struct Iota(N,S) if (isFloatingPoint!(N) && isNumeric!(S));
Returns a range that goes through the numbers begin, begin + step, begin + 2 * step, ..., up to and excluding end. The range offered is a random access range. The two-arguments version has step = 1.

Example:
auto r = iota(0, 10, 1);
assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][]));
r = iota(0, 11, 3);
assert(equal(r, [0, 3, 6, 9][]));
assert(r[2] == 6);
auto rf = iota(0.0, 0.5, 0.1);
assert(approxEqual(rf, [0.0, 0.1, 0.2, 0.3, 0.4]));

enum TransverseOptions;
Options for the FrontTransversal and Transversal ranges (below).

assumeJagged
When transversed, the elements of a range of ranges are assumed to have different lengths (e.g. a jagged array).

enforceNotJagged
The transversal enforces that the elements of a range of ranges have all the same length (e.g. an array of arrays, all having the same length). Checking is done once upon construction of the transversal range.

assumeNotJagged
The transversal assumes, without verifying, that the elements of a range of ranges have all the same length. This option is useful if checking was already done from the outside of the range.

struct FrontTransversal(Ror,TransverseOptions opt = TransverseOptions.assumeJagged);
FrontTransversal!(RangeOfRanges,opt) frontTransversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr);
Given a range of ranges, iterate transversally through the first elements of each of the enclosed ranges.

Example:
int[][] x = new int[][2];
x[0] = [1, 2];
x[1] = [3, 4];
auto ror = frontTransversal(x);
assert(equal(ror, [ 1, 3 ][]));

__ctor;
Construction from an input.

bool empty;
ElementType moveFront();
void popFront();
typeof(this) save();
void popBack();
ElementType moveBack();
ElementType moveAt(size_t n);
void opIndexAssign(ElementType val, size_t n);
Forward range primitives.

typeof(this) opSlice(size_t lower, size_t upper);
Slicing if offered if RangeOfRanges supports slicing and all the conditions for supporting indexing are met.

struct Transversal(Ror,TransverseOptions opt = TransverseOptions.assumeJagged);
Transversal!(RangeOfRanges,opt) transversal(TransverseOptions opt = TransverseOptions.assumeJagged, RangeOfRanges)(RangeOfRanges rr, size_t n);
Given a range of ranges, iterate transversally through the the nth element of each of the enclosed ranges. All elements of the enclosing range must offer random access.

Example:
int[][] x = new int[][2];
x[0] = [1, 2];
x[1] = [3, 4];
auto ror = transversal(x, 1);
assert(equal(ror, [ 2, 4 ][]));

__ctor;
Construction from an input and an index.

bool empty;
E moveFront();
front(E val);
void popFront();
typeof(this) save();
void popBack();
E moveBack();
back(E val);
E moveAt(size_t n);
void opIndexAssign(E val, size_t n);
Forward range primitives.

typeof(this) opSlice(size_t lower, size_t upper);
Slicing if offered if RangeOfRanges supports slicing and all the conditions for supporting indexing are met.

ElementType!(R) moveFront(R)(R r);
Moves the front of r out and returns it. Leaves r.front in a destroyable state that does not allocate any resources (usually equal to its .init value).

ElementType!(R) moveBack(R)(R r);
Moves the back of r out and returns it. Leaves r.back in a destroyable state that does not allocate any resources (usually equal to its .init value).

ElementType!(R) moveAt(R)(R r, size_t i);
Moves element at index i of r out and returns it. Leaves r.front in a destroyable state that does not allocate any resources (usually equal to its .init value).

interface InputRange(E);
These interfaces are intended to provide virtual function-based wrappers around input ranges with element type E. This is useful where a well-defined binary interface is required, such as when a DLL function or virtual function needs to accept a generic range as a parameter. Note that isInputRange and friends check for conformance to structural interfaces, not for implementation of these interface types.

Examples:
 class UsesRanges {
     void useRange(InputRange range) {
         // Function body.
     }
 }

 // Create a range type.
 auto squares = map!"a * a"(iota(10));

 // Wrap it in an interface.
 auto squaresWrapped = inputRangeObject(squares);

 // Use it.
 auto usesRanges = new UsesRanges;
 usesRanges.useRange(squaresWrapped);

Limitations:
These interfaces are not capable of forwarding ref access to elements.

Infiniteness of the wrapped range is not propagated.

Length is not propagated in the case of non-random access ranges.

E front();

E moveFront();

void popFront();

bool empty();

int opApply(int delegate(ref E));
int opApply(int delegate(ref size_t, ref E));
foreach iteration uses opApply, since one delegate call per loop iteration is faster than three virtual function calls.

BUGS:
If a ref variable is provided as the loop variable, changes made to the loop variable will not be propagated to the underlying range. If the address of the loop variable is escaped, undefined behavior will result. This is related to DMD bug 2443.

interface ForwardRange(E): InputRange!(E);
Interface for a forward range of type E.

ForwardRange!(E) save();

interface BidirectionalRange(E): ForwardRange!(E);
Interface for a bidirectional range of type E.

BidirectionalRange!(E) save();

E back();

E moveBack();

void popBack();

interface RandomAccessFinite(E): BidirectionalRange!(E);
Interface for a finite random access range of type E.

RandomAccessFinite!(E) save();

E opIndex(size_t);

E moveAt(size_t);

size_t length();

RandomAccessFinite!(E) opSlice(size_t, size_t);

interface RandomAccessInfinite(E): ForwardRange!(E);
Interface for an infinite random access range of type E.

E moveAt(size_t);

RandomAccessInfinite!(E) save();

E opIndex(size_t);

interface InputAssignable(E): InputRange!(E);
Adds assignable elements to InputRange.

void front(E newVal);

interface ForwardAssignable(E): InputAssignable!(E), ForwardRange!(E);
Adds assignable elements to ForwardRange.

ForwardAssignable!(E) save();

interface BidirectionalAssignable(E): ForwardAssignable!(E), BidirectionalRange!(E);
Adds assignable elements to BidirectionalRange.

BidirectionalAssignable!(E) save();

void back(E newVal);

interface RandomFiniteAssignable(E): RandomAccessFinite!(E), BidirectionalAssignable!(E);
Adds assignable elements to RandomAccessFinite.

RandomFiniteAssignable!(E) save();

void opIndexAssign(E val, size_t index);

interface OutputRange(E);
Interface for an output range of type E. Usage is similar to the InputRange interface and descendants.

void put(E);

class OutputRangeObject(R,E...): staticMap!(OutputRange,E);
Implements the OutputRange interface for all types E and wraps the put method for each type E in a virtual function.

template MostDerivedInputRange(R) if (isInputRange!(Unqual!(R)))
Returns the interface type that best matches R.

template InputRangeObject(R) if (isInputRange!(Unqual!(R)))
Implements the most derived interface that R works with and wraps all relevant range primitives in virtual functions. If R is already derived from the InputRange interface, aliases itself away.

InputRangeObject!(R) inputRangeObject(R)(R range);
Convenience function for creating a InputRangeObject of the proper type.

template outputRangeObject(E...)
Convenience function for creating a OutputRangeObject with a base range of type R that accepts types E.

Examples:
uint[] outputArray;
auto app = appender(&outputArray);
auto appWrapped = outputRangeObject!(uint, uint[])(app);
static assert(is(typeof(appWrapped) : OutputRange!(uint[])));
static assert(is(typeof(appWrapped) : OutputRange!(uint)));

template outputRangeObject(R)

OutputRangeObject!(R,E) outputRangeObject(R range);

struct SortedRange(Range,alias pred = "a < b") if (isRandomAccessRange!(Unqual!(Range)));
Represents a sorted random-access range. In addition to the regular range primitives, supports fast operations using binary search. To obtain a SortedRange from an unsorted range r, use std.algorithm.sort which sorts r in place and returns the corresponding SortedRange. To construct a SortedRange from a range r that is known to be already sorted, use assumeSorted described below.

Example:
auto a = [ 1, 2, 3, 42, 52, 64 ];
auto r = assumeSorted(a);
assert(r.canFind(3));
assert(!r.canFind(32));
auto r1 = sort!"a > b"(a);
assert(r1.canFind(3));
assert(!r1.canFind(32));
assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]);
SortedRange could accept ranges weaker than random-access, but it is unable to provide interesting functionality for them. Therefore, SortedRange is currently restricted to random-access ranges.

No copy of the original range is ever made. If the underlying range is changed concurrently with its corresponding SortedRange in ways that break its sortedness, SortedRange will work erratically.

Example:
auto a = [ 1, 2, 3, 42, 52, 64 ];
auto r = assumeSorted(a);
assert(r.canFind(42));
swap(a[2], a[5]); // illegal to break sortedness of original range
assert(!r.canFind(42)); // passes although it shouldn't

bool empty();
typeof(this) save();
ElementType!(R) front();
void popFront();
ElementType!(R) back();
void popBack();
ElementType!(R) opIndex(size_t i);
typeof(this) opSlice(size_t a, size_t b);
size_t length();
Range primitives.

R release();
Releases the controlled range and returns it.

template lowerBound(V)
This function assumes that range r consists of a subrange r1 of elements e1 for which pred(e1, value) is true, followed by a subrange r2 of elements e2 for which pred(e2, value) is false. Using this assumption, lowerBound uses binary search to find r1, i.e. the left subrange on which pred is always true. Performs Ο(log(r.length)) evaluations of pred. The precondition is not verified because it would deteriorate function's complexity. It is possible that the types of value and ElementType!(Range) are different, if the predicate accepts them. See also STL's lower_bound.

Precondition:
find!(not!(pred))(r, value).length + find!(pred)(retro(r), value).length == r.length

Example:
   auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
   auto p = a.lowerBound(4);
   assert(p.release == [ 0, 1, 2, 3 ]);

typeof(this) lowerBound(V value);
This function assumes that range r consists of a subrange r1 of elements e1 for which pred(e1, value) is true, followed by a subrange r2 of elements e2 for which pred(e2, value) is false. Using this assumption, lowerBound uses binary search to find r1, i.e. the left subrange on which pred is always true. Performs Ο(log(r.length)) evaluations of pred. The precondition is not verified because it would deteriorate function's complexity. It is possible that the types of value and ElementType!(Range) are different, if the predicate accepts them. See also STL's lower_bound.

Precondition:
find!(not!(pred))(r, value).length + find!(pred)(retro(r), value).length == r.length

Example:
   auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]);
   auto p = a.lowerBound(4);
   assert(p.release == [ 0, 1, 2, 3 ]);

template upperBound(V)
This function assumes that range r consists of a subrange r1 of elements e1 for which pred(value, e1) is false, followed by a subrange r2 of elements e2 for which pred(value, e2) is true. (Note the differences in subrange definition and argument order for pred compared to lowerBound.) Using this assumption, upperBound uses binary search to find r2, i.e. the right subrange on which pred is always true. Performs Ο(log(r.length)) evaluations of pred. The precondition is not verified because it would deteriorate function's complexity. It is possible that the types of value and ElementType!(Range) are different, if the predicate accepts them. See also STL's upper_bound.

Precondition:
find!(pred)(r, value).length + find!(not!(pred))(retro(r), value).length == r.length

Example:
   auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
   auto p = a.upperBound(3);
   assert(p == [4, 4, 5, 6]);

typeof(this) upperBound(V value);
This function assumes that range r consists of a subrange r1 of elements e1 for which pred(value, e1) is false, followed by a subrange r2 of elements e2 for which pred(value, e2) is true. (Note the differences in subrange definition and argument order for pred compared to lowerBound.) Using this assumption, upperBound uses binary search to find r2, i.e. the right subrange on which pred is always true. Performs Ο(log(r.length)) evaluations of pred. The precondition is not verified because it would deteriorate function's complexity. It is possible that the types of value and ElementType!(Range) are different, if the predicate accepts them. See also STL's upper_bound.

Precondition:
find!(pred)(r, value).length + find!(not!(pred))(retro(r), value).length == r.length

Example:
   auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]);
   auto p = a.upperBound(3);
   assert(p == [4, 4, 5, 6]);

template equalRange(V)
Assuming a range satisfying both preconditions for lowerBound!(pred)(r, value) and upperBound!(pred)(r, value), the call equalRange!(pred)(r, v) returns the subrange containing all elements e for which both pred(e, value) and pred(value, e) evaluate to false. Performs Ο(log(r.length)) evaluations of pred. See also STL's equal_range.

Precondition:
find!(not!(pred))(r, value).length + find!(pred)(retro(r), value).length == r.length && find!(pred)(r, value).length + find!(not!(pred))(retro(r), value).length == r.length

Example:
   auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
   auto r = equalRange(a, 3);
   assert(r == [ 3, 3, 3 ]);

typeof(this) equalRange(V value);
Assuming a range satisfying both preconditions for lowerBound!(pred)(r, value) and upperBound!(pred)(r, value), the call equalRange!(pred)(r, v) returns the subrange containing all elements e for which both pred(e, value) and pred(value, e) evaluate to false. Performs Ο(log(r.length)) evaluations of pred. See also STL's equal_range.

Precondition:
find!(not!(pred))(r, value).length + find!(pred)(retro(r), value).length == r.length && find!(pred)(r, value).length + find!(not!(pred))(retro(r), value).length == r.length

Example:
   auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ];
   auto r = equalRange(a, 3);
   assert(r == [ 3, 3, 3 ]);

template canFind(V)
Returns true if and only if value can be found in range, which is assumed to be sorted. Performs Ο(log(r.length)) evaluations of pred. See also STL's binary_search.

bool canFind(V value);
Returns true if and only if value can be found in range, which is assumed to be sorted. Performs Ο(log(r.length)) evaluations of pred. See also STL's binary_search.

Copyright Andrei Alexandrescu 2008-. | Page generated by Ddoc.


std.regex

Regular expressions are a powerful method of string pattern matching. The regular expression language used in this library is the same as that commonly used, however, some of the very advanced forms may behave slightly differently. The standard observed is the ECMA standard for regular expressions.

std.regex is designed to work only with valid UTF strings as input - UTF8 (char), UTF16 (wchar), or UTF32 (dchar). 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

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

string email;
Regular expression to extract an email address.

References:
How to Find or Validate an Email Address; RFC 2822 Internet Message Format

string url;
Regular expression to extract a url

struct Regex(E) if (is(E == Unqual!(E)));
Regex!(Unqual!(typeof(String.init[0]))) regex(String)(String pattern, string flags = null);
A Regex stores a regular expression engine. A Regex object is constructed from a string and compiled into an internal format for performance.

The type parameter E specifies the character type recognized by the regular expression. Currently char, wchar, and dchar are supported. The encoding of the regex string and of the recognized strings must be the same.

This object will be mostly used via a call to the regex function, which automatically deduces the character type.

Example:
Declare two variables and assign to them a Regex object. The first matches UTF-8 strings, the second matches UTF-32 strings and also has the global option set.

auto r = regex("pattern");
auto s = regex(r"p[1-5]\s*"w, "g");

template __ctor(String)
Construct a Regex object. Compile pattern with attributes into an internal form for fast execution.

Parameters:
pattern | regular expression
attributes | The attributes (g, i, and m accepted)

Throws:
Exception if there are any compilation errors.

const uint captures();
Returns the number of parenthesized captures

struct RegexMatch(Range = string);
RegexMatch is the type returned by a call to match. It stores the matching state and can be inspected and iterated.

Regex engine;
Get or set the engine of the match.

const bool empty();
void popFront();
RegexMatch!(Range) front();
typeof(this) save();
Range primitives that allow incremental matching against a string.

Example:
import std.stdio;
import std.regex;

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

Captures captures();
Retrieve the captured parenthesized matches, in the form of a random-access range. The first element in the range is always the full match.

Example:
foreach (m; match("abracadabra", "(.)a(.)"))
{
    foreach (c; m.captures)
        write(c, ';');
    writeln();
}
// writes:
// rac;r;c;
// dab;d;b;

Range pre();
Returns the slice of the input that precedes the matched substring.

Range hit();
The matched portion of the input.

Range post();
Returns the slice of the input that follows the matched substring.

string toString();
Returns hit (converted to string if necessary).

bool chr(ref size_t si, E c);
Returns whether string s matches this.

RegexMatch!(Range) match(Range, Engine)(Range r, Engine engine);
Matches a string against a regular expression. This is the main entry to the module's functionality. A call to match(input, regex) returns a RegexMatch object that can be used for direct inspection or for iterating over all matches (if the regular expression was built with the "g" option).

Range replace(Range, Engine, String)(Range input, Engine regex, String format);
Search string for matches with regular expression pattern with attributes. Replace the first match with string generated from format. If the regular expression has the "g" (global) attribute, continue and replace all matches.

Parameters:
input | Range to search.
regex | Regular expression pattern.
format | Replacement string format.

Returns:
The resulting string.

Example:
s = "ark rapacity";
assert(replace(s, regex("r"), "c") == "ack rapacity");
assert(replace(s, regex("r", "g"), "c") == "ack capacity");
The replacement format can reference the matches using the $&, $$, $', $`, .. 9 notation:

assert(replace("noon", regex("^n"), "[$&]") == "[n]oon");

Range replace(alias fun, Range, Regex)(Range s, Regex rx);
Search string for matches with regular expression pattern with attributes. Pass each match to function fun. Replace each match with the return value from dg.

Parameters:
s | String to search.
pattern | Regular expression pattern.
dg | Delegate

Returns:
the resulting string.

Example:
Capitalize the letters 'a' and 'r':
string baz(RegexMatch!(string) m)
{
    return std.string.toupper(m.hit);
}
auto s = replace!(baz)("Strap a rocket engine on a chicken.",
        regex("[ar]", "g"));
assert(s == "StRAp A Rocket engine on A chicken.");

struct Splitter(Range);
Splitter!(Range) splitter(Range, Regex)(Range r, Regex pat);
Range that splits another range using a regular expression as a separator.

Example:
auto s1 = ", abc, de,  fg, hi, ";
assert(equal(splitter(s1, regex(", *")),
    ["", "abc", "de", "fg", "hi", ""][]));

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.regexp

Regular expressions are a powerful method of string pattern matching. The regular expression language used in this library is the same as that commonly used, however, some of the very advanced forms may behave slightly differently. The standard observed is the ECMA standard for regular expressions.

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

License:
Boost License 1.0.

Authors:
Walter Bright

string email;
Regular expression to extract an email address.

References:
How to Find or Validate an Email Address
RFC 2822 Internet Message Format

string url;
Regular expression to extract a url

class RegExpException: object.Exception;
One of these gets thrown on compilation errors

string sub(string s, string pattern, string format, string attributes = null);
Search string for matches with regular expression pattern with attributes. Replace each match with string generated from format.

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string format | Replacement string format.
string 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

string sub(string s, string pattern, string delegate(RegExp) dg, string 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.

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string delegate(RegExp) dg | Delegate
string 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[0]);
    },
    "g");    // result: StRAp A Rocket engine on A chicken.

sizediff_t find(string s, RegExp pattern);
Search s[] for first match with pattern.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
index into s[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 find(s, RegExp("b"));    // match, returns 1
 find(s, RegExp("f"));    // no match, returns -1

sizediff_t find(string s, string pattern, string attributes = null);
Returns:
Same as find(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.find(s, p, a), you may want to use find(s, RegExp(p, a)).

sizediff_t rfind(string s, RegExp pattern);
Search s[] for last match with pattern.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
index into s[] of match if found, -1 if no match.

Example:
 auto s = "abcabcabab";
 rfind(s, RegExp("b"));    // match, returns 9
 rfind(s, RegExp("f"));    // no match, returns -1

sizediff_t rfind(string s, string pattern, string attributes = null);
Returns:
Same as rfind(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.rfind(s, p, a), you may want to use rfind(s, RegExp(p, a)).

string[] split(string s, RegExp pattern);
Split s[] into an array of strings, using the regular expression pattern as the separator.

Parameters:
string s | String to search.
RegExp pattern | Regular expression pattern.

Returns:
array of slices into s[]

Example:
 foreach (s; split("abcabcabab", RegExp("C.", "i")))
 {
     writefln("s = '%s'", s);
 }
 // Prints:
 // s = 'ab'
 // s = 'b'
 // s = 'bab'

string[] split(string s, string pattern, string attributes = null);
Returns:
Same as split(s, RegExp(pattern, attributes)).

WARNING:
This function is scheduled for deprecation due to unnecessary ambiguity with the homonym function in std.string. Instead of std.regexp.split(s, p, a), you may want to use split(s, RegExp(p, a)).

RegExp search(string s, string pattern, string attributes = null);
Search s[] for first match with pattern[] with attributes[].

Parameters:
string s | String to search.
string pattern | Regular expression pattern.
string 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[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(string pattern, string attributes = null);
Construct a RegExp object. Compile pattern with attributes into an internal form for fast execution.

Parameters:
string pattern | regular expression
string 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(string pattern, string attributes = null);
Generate instance of RegExp.

Parameters:
string pattern | regular expression
string 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(string string);
int opApply(scope 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[0], m.post);
     }
 }
 // Prints:
 // [ab]cabcabab
 // abc[ab]cabab
 // abcabc[ab]ab
 // abcabcab[ab]

string opIndex(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.

string match(size_t n);
Same as opIndex(n).

WARNING:
Scheduled for deprecation due to confusion with overloaded match(string). Instead of regex.match(n) you may want to use regex[n].

string pre();
Return the slice of the input that precedes the matched substring.

string post();
Return the slice of the input that follows the matched substring.

string[] split(string s);
Split s[] into an array of strings, using the regular expression as the separator.

Returns:
array of slices into s[]

size_t find(string string);
Search string[] for match with regular expression.

Returns:
index of match if successful, -1 if not found

string[] match(string s);
Search s[] for match.

Returns:
If global attribute, return same value as exec(s). If not global attribute, return array of all matches.

string replace(string s, string format);
Find regular expression matches in s[]. 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

string[] exec(string string);
Search string[] for match.

Returns:
array of slices into string[] representing matches

string[] exec();
Pick up where last exec(string) or exec() left off, searching string[] for next match.

Returns:
array of slices into string[] representing matches

bool test(string s);
Search s[] 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(string s, size_t startindex);
Test s[] starting at startindex against regular expression.

Returns:
0 for no match, !=0 for match

alias opEquals;
Returns whether string s matches this.

string replace(string 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.

string replaceOld(string 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 Digital Mars 2000 - 2009. | 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.

License:
Boost License 1.0.

Authors:
Walter Bright

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(string 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!(string, 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.

Copyright Digital Mars 2000 - 2009. | 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

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;
uint[] 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);
Parameters:
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.

Select!(false,long,int) send(const(void)[] buf, SocketFlags flags);
Select!(false,long,int) send(const(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.

Select!(false,long,int) sendTo(const(void)[] buf, SocketFlags flags, Address to);
Select!(false,long,int) sendTo(const(void)[] buf, Address to);
Select!(false,long,int) sendTo(const(void)[] buf, SocketFlags flags);
Select!(false,long,int) sendTo(const(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.

ptrdiff_t receive(void[] buf, SocketFlags flags);
ptrdiff_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.

Select!(false,long,int) receiveFrom(void[] buf, SocketFlags flags, out Address from);
ptrdiff_t receiveFrom(void[] buf, out Address from);
Select!(false,long,int) receiveFrom(void[] buf, SocketFlags flags);
ptrdiff_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-2010 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

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(const void* _buffer, size_t size);
Attempts to write the entire block, waiting if necessary.

ulong seek(long offset, SeekPos whence);

string toString();
Does not return the entire stream because that would require the remote connection to be closed.

void close();
Close the Socket.

Copyright © 1999-2010 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

License:
Boost License 1.0.

Authors:
Walter Bright

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.stdio

Standard I/O functions that extend std.c.stdio. std.c.stdio is publically imported when importing std.stdio.

Source:
std/stdio.d

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

struct File;
Encapsulates a FILE*. Generally D does not attempt to provide thin wrappers over equivalent functions in the C standard library, but manipulating FILE* values directly is unsafe and error-prone in many ways. The File type ensures safe manipulation, automatic file closing, and a lot of convenience.

The underlying FILE* handle is maintained in a reference-counted manner, such that as soon as the last File variable bound to a given FILE* goes out of scope, the underlying FILE* is automatically closed.

Example:
// test.d
void main(string args[])
{
    auto f = File("test.txt", "w"); // open for writing
    f.write("Hello");
    if (args.length > 1)
    {
        auto g = f; // now g and f write to the same file
                    // internal reference count is 2
        g.write(", ", args[1]);
        // g exits scope, reference count decreases to 1
    }
    f.writeln("!");
    // f exits scope, reference count falls to zero,
    // underlying FILE* is closed.
}

% rdmd test.d Jimmy
% cat test.txt
Hello, Jimmy!
% _

this(string name, in char[] stdioOpenmode = "rb");
Constructor taking the name of the file to open and the open mode (with the same semantics as in the C standard library fopen function). Throws an exception if the file could not be opened.

Copying one File object to another results in the two File objects referring to the same underlying file.

The destructor automatically closes the file as soon as no File object refers to it anymore.

void opAssign(File rhs);
Assigns a file to another. The target of the assignment gets detached from whatever file it was attached to, and attaches itself to the new file.

void open(string name, in char[] stdioOpenmode = "rb");
First calls detach (throwing on failure), and then attempts to open file name with mode stdioOpenmode. The mode has the same semantics as in the C standard library fopen function. Throws exception in case of error.

const bool isOpen();
Returns true if the file is opened.

const bool eof();
Returns true if the file is at end (see feof). The file must be opened, otherwise an exception is thrown.

const string name();
Returns the name of the file, if any.

const bool error();
If the file is not opened, returns false. Otherwise, returns ferror for the file handle.

void detach();
Detaches from the underlying file. If the sole owner, calls close and throws if that fails.

void close();
If the file was unopened, succeeds vacuously. Otherwise closes the file (by calling fclose), throwing on error. Even if an exception is thrown, afterwards the File object is empty. This is different from detach in that it always closes the file; consequently, all other File objects referring to the same handle will see a closed file henceforth.

void clearerr();
If the file is not opened, succeeds vacuously. Otherwise, returns clearerr for the file handle.

void flush();
If the file is not opened, throws an exception. Otherwise, calls fflush for the file handle and throws on error.

T[] rawRead(T)(T[] buffer);
If the file is not opened, throws an exception. Otherwise, calls fread for the file handle and throws on error.

rawRead always read in binary mode on Windows.

void rawWrite(T)(in T[] buffer);
If the file is not opened, throws an exception. Otherwise, calls fwrite for the file handle and throws on error.

rawWrite always write in binary mode on Windows.

void seek(long offset, int origin = SEEK_SET);
If the file is not opened, throws an exception. Otherwise, calls fseek for the file handle. Throws on error.

const ulong tell();
If the file is not opened, throws an exception. Otherwise, calls ftell for the managed file handle. Throws on error.

void rewind();
If the file is not opened, throws an exception. Otherwise, calls rewind for the file handle. Throws on error.

void setvbuf(size_t size, int mode = _IOFBF);
If the file is not opened, throws an exception. Otherwise, calls setvbuf for the file handle.

void setvbuf(void[] buf, int mode = _IOFBF);
If the file is not opened, throws an exception. Otherwise, calls setvbuf for the file handle.

void write(S...)(S args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file.

void writeln(S...)(S args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file, followed by a newline.

void writef(S...)(S args);
If the file is not opened, throws an exception. Otherwise, writes its arguments in text format to the file, according to the format in the first argument.

void writefln(S...)(S args);
Same as writef, plus adds a newline.

S readln(S = string)(dchar terminator = '\x0a');
size_t readln(C)(ref C[] buf, dchar terminator = '\x0a');
size_t readln(C, R)(ref C[] buf, R terminator);
Read line from stream fp and write it to buf[], including terminating character.

This is often faster than File.readln(dchar) because the buffer is reused each call. Note that reusing the buffer means that the previous contents of it has to be copied if needed.

Parameters:
fp | input stream
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 (stdin.readln(buf))
        write(buf);
    return 0;
}
This method is more efficient than the one in the previous example because stdin.readln(buf) reuses (if possible) memory allocated by buf, whereas buf = stdin.readln() makes a new memory allocation with every line.

static File tmpfile();
Returns a temporary file by calling tmpfile.

static File wrapFile(shared(_iobuf)* f);
Unsafe function that wraps an existing FILE*. The resulting File never takes the initiative in closing the file.

shared(_iobuf)* getFP();
Returns the FILE* corresponding to this object.

const int fileno();
Returns the file number corresponding to this object.

enum KeepTerminator;
struct ByLine(Char,Terminator);
Range that reads one line at a time.

ByLine!(Char,Terminator) byLine(Terminator = char, Char = char)(KeepTerminator keepTerminator = KeepTerminator.no, Terminator terminator = '\x0a');
Convenience function that returns the LinesReader corresponding to this file.

struct ByChunk;
Range that reads a chunk at a time.

const bool empty();
ubyte[] front();
void popFront();
Range primitive operations.

ByChunk byChunk(size_t chunkSize);
Iterates through a file a chunk at a time by using foreach.

Example:
void main()
{
  foreach (ubyte[] buffer; stdin.byChunk(4096))
  {
    ... use buffer ...
  }
}
The content of buffer is reused across calls. In the example above, buffer.length is 4096 for all iterations, except for the last one, in which case buffer.length may be less than 4096 (but always greater than zero).

In case of an I/O error, an StdioException is thrown.

struct LockingTextWriter;
Range that locks the file and allows fast writing to it.

void put(A)(A writeme);
void put(C)(C c);
Range primitive implementations.

LockingTextWriter lockingTextWriter();
Convenience function.

void write(T...)(T args);
For each argument arg in args, format the argument (as per to!(string)(arg)) and write the resulting string to args[0]. A call without any arguments will fail to compile.

Throws:
In case of an I/O error, throws an StdioException.

void writeln(T...)(T args);
void writeln(T...)(T args);
void writeln(T...)(T args);
Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

void writef(T...)(T args);
If the first argument args[0] is a FILE*, use the format specifier in args[1] to control the formatting of args[2..$], and write the resulting string to args[0]. If arg[0] is not a FILE*, the call is equivalent to writef(stdout, args).

IMPORTANT:
New behavior starting with D 2.006: unlike previous versions, writef (and also writefln) only scans its first string argument for format specifiers, but not subsequent string arguments. This decision was made because the old behavior made it unduly hard to simply print string variables that occasionally embedded percent signs.

Also new starting with 2.006 is support for positional parameters with POSIX syntax.

Example:
writef("Date: %2$s %1$s", "October", 5); // "Date: 5 October"
The positional and non-positional styles can be mixed in the same format string. (POSIX leaves this behavior undefined.) The internal counter for non-positional parameters tracks the popFront parameter after the largest positional parameter already used.

New starting with 2.008: raw format specifiers. Using the "%r" specifier makes writef simply write the binary representation of the argument. Use "%-r" to write numbers in little endian format, "%+r" to write numbers in big endian format, and "%r" to write numbers in platform-native format.

void writefln(T...)(T args);
Equivalent to writef(args, '\n').

void readf(A...)(in char[] format, A args);
Formatted read one line from stdin.

string readln(dchar terminator = '\x0a');
size_t readln(ref char[] buf, dchar terminator = '\x0a');
Read line from stream fp.

Returns:
null for end of file, char[] for line read from fp, including terminating character

Parameters:

Throws:
StdioException on error

Example:
Reads stdin and writes it to stdout.
import std.stdio;

int main()
{
    char[] buf;
    while ((buf = readln()) != null)
        write(buf);
    return 0;
}

struct lines;
Iterates through the lines of a file by using foreach.

Example:
void main()
{
  foreach (string line; lines(stdin))
  {
    ... use line ...
  }
}
The line terminator ('\n' by default) is part of the string read (it could be missing in the last line of the file). Several types are supported for line, and the behavior of lines changes accordingly:

  1. If line has type string, wstring, or dstring, a new string of the respective type is allocated every read.
  2. If line has type char[], wchar[], dchar[], the line's content will be reused (overwritten) across reads.
  3. If line has type immutable(ubyte)[], the behavior is similar to case (1), except that no UTF checking is attempted upon input.
  4. If line has type ubyte[], the behavior is similar to case (2), except that no UTF checking is attempted upon input.

In all cases, a two-symbols versions is also accepted, in which case the first symbol (of integral type, e.g. ulong or uint) tracks the zero-based number of the current line.

Example:
  foreach (ulong i, string line; lines(stdin))
  {
    ... use line ...
  }
In case of an I/O error, an StdioException is thrown.

struct chunks;
Iterates through a file a chunk at a time by using foreach.

Example:
void main()
{
  foreach (ubyte[] buffer; chunks(stdin, 4096))
  {
    ... use buffer ...
  }
}
The content of buffer is reused across calls. In the example above, buffer.length is 4096 for all iterations, except for the last one, in which case buffer.length may be less than 4096 (but always greater than zero).

In case of an I/O error, an StdioException is thrown.

class StdioException: object.Exception;
Thrown if I/O errors happen.

uint errno;
Operating system error code.

this(string message, uint e = module stdio.getErrno);
Initialize with a message and an error code.

static void opCall(string msg);
static void opCall();
Convenience functions that throw an StdioException.

Copyright Digital Mars 2007-. | 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.

License:
Boost License 1.0.

Authors:
Ben Hinkle

class CFile: std.stream.Stream;
A Stream wrapper for a C file of type FILE*.

this(shared(_iobuf)* cfile, FileMode mode, bool seekable = false);
Create the stream wrapper for the given C file.

Parameters:
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.

shared(_iobuf)* file();
void file(shared(_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(const void* buffer, size_t size);
ulong seek(long offset, SeekPos rel);
void writeLine(const(char)[] s);
void writeLineW(const(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 Ben Hinkle 2007 - 2009. | Page generated by Ddoc.


std.stream

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(scope int delegate(ref char[] line) dg);
abstract int opApply(scope int delegate(ref ulong n, ref char[] line) dg);
abstract int opApply(scope int delegate(ref wchar[] line) dg);
abstract int opApply(scope 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, void* 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(const 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(const(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(const(char)[] s);
abstract void write(const(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(const(char)[] s);
Write a line of text, appending the line with an operating-system-specific line ending.

Throws WriteException on error.

abstract void writeLineW(const(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(const(char)[] s);
Write a string of text.

Throws WriteException if it could not be fully written.

abstract void writeStringW(const(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(const(char)[] format, va_list args);
abstract size_t printf(const(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(const 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, size_t 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, size_t bufferSize = DefaultBufferSize);
opens file in requested mode and buffer size

this(File file, size_t bufferSize = DefaultBufferSize);
opens file for reading with requested buffer size

this(HANDLE hFile, FileMode mode, size_t 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(const(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.

__ctor;
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-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.string

String handling functions. Objects of types string, wstring, and dstring are value types and cannot be mutated element-by-element. For using mutation during building strings, use char[], wchar[], or dchar[]. The *string types are preferable because they don't exhibit undesired aliasing, thus making code more robust.

License:
Boost License 1.0.

Authors:
Walter Bright, Andrei Alexandrescu

typedef StringException;
Thrown on errors in string functions.

immutable char[16u] hexdigits;
0..9A..F

immutable char[10u] digits;
0..9

immutable char[8u] octdigits;
0..7

immutable char[26u] lowercase;
a..z

immutable char[52u] letters;
A..Za..z

immutable char[26u] uppercase;
A..Z

immutable char[6u] whitespace;
ASCII whitespace

dchar LS;
UTF line separator

dchar PS;
UTF paragraph separator

immutable char[2u] newline;
Newline sequence for this system

bool iswhite(dchar c);
Returns true if c is whitespace

int cmp(C1, C2)(in C1[] s1, in C2[] s2);
sizediff_t icmp(C1, C2)(in C1[] s1, in C2[] s2);
Compare two strings. cmp is case sensitive, icmp is case insensitive.

Returns:
< 0 | s1 < s2
= 0 | s1 == s2
> 0 | s1 > s2

immutable(char)* toStringz(const(char)[] s);
immutable(char)* toStringz(string s);
Convert array of chars s[] to a C-style 0-terminated string. s[] must not contain embedded 0's.

enum CaseSensitive;
Flag indicating whether a search is case-sensitive.

sizediff_t indexOf(Char)(in Char[] s, dchar c, CaseSensitive cs = CaseSensitive.yes);
ptrdiff_t lastIndexOf(in char[] s, dchar c, CaseSensitive cs = (CaseSensitive).yes);
indexOf: find first occurrence of c in string s. lastIndexOf: find last occurrence of c in string s. CaseSensitive.yes means the searches are case sensitive.

Returns:
Index in s where c is found, -1 if not found.

sizediff_t indexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub, CaseSensitive cs = CaseSensitive.yes);
ptrdiff_t lastIndexOf(in char[] s, in char[] sub, CaseSensitive cs = (CaseSensitive).yes);
indexOf find first occurrence of sub[] in string s[]. lastIndexOf find last occurrence of sub[] in string s[].

CaseSensitive cs controls whether the comparisons are case sensitive or not.

Returns:
Index in s where sub is found, -1 if not found.

S tolower(S)(S s);
Convert string s[] to lower case.

void tolowerInPlace(C)(ref C[] s);
Converts s to lowercase in place.

S toupper(S)(S s);
Convert string s[] to upper case.

void toupperInPlace(C)(ref C[] s);
Converts s to uppercase in place.

string capitalize(string s);
Capitalize first character of string s[], convert rest of string s[] to lower case.

string capwords(string s);
Capitalize all words in string s[]. Remove leading and trailing whitespace. Replace all sequences of whitespace with a single space.

string repeat(string s, size_t n);
Return a string that consists of s[] repeated n times.

string join(in string[] words, string sep);
Concatenate all the strings in words[] together into one string; use sep[] as the separator.

S[] split(S)(S s);
Split s[] into an array of words, using whitespace as delimiter.

Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim);
Split s[] into an array of words, using delim[] as the delimiter.

S[] splitlines(S)(S 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.

String stripl(String)(String s);
String stripr(String)(String s);
String strip(String)(String s);
Strips leading or trailing whitespace, or both.

C[] chomp(C)(C[] s);
C[] chomp(C, C1)(C[] s, in C1[] delimiter);
Returns s[] sans trailing delimiter[], if any. If delimiter[] is null, removes trailing CR, LF, or CRLF, if any.

C1[] chompPrefix(C1, C2)(C1[] longer, C2[] shorter);
If longer.startsWith(shorter), returns longer[shorter.length .. $]. Otherwise, returns longer.

string chop(string s);
Returns s[] sans trailing character, if there is one. If last two characters are CR-LF, then both are removed.

string ljustify(string s, size_t width);
string rjustify(string s, size_t width);
string center(string s, int width);
Left justify, right justify, or center string s[] in field width chars wide.

string zfill(string s, int width);
Same as rjustify(), but fill with '0's.

string replace(string s, string from, string to);
Replace occurrences of from[] with to[] in s[].

string replaceSlice(string s, in string slice, in string replacement);
Return a string that is s[] with slice[] replaced by replacement[].

string insert(string s, size_t index, string sub);
Insert sub[] into s[] at location index.

size_t count(in char[] s, in char[] sub);
Count up all instances of sub[] in s[].

string expandtabs(string str, int tabsize = 8);
Replace tabs with the appropriate number of spaces. tabsize is the distance between tab stops.

string entab(string s, int tabsize = 8);
Replace spaces in string s with the optimal number of tabs. Trailing spaces or tabs in a line are removed.

Parameters:
string s | String to convert.
int tabsize | Tab columns are tabsize spaces apart. tabsize defaults to 8.

string maketrans(in string from, in string to);
Construct translation table for translate().

BUG:
only works with ASCII

string translate(string s, in string transtab, in string delchars);
Translate characters in s[] using table created by maketrans(). Delete chars in delchars[].

BUG:
only works with ASCII

string 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 RangeError if it is not.

Returns:
s

bool inPattern(dchar c, in string 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, string[] patterns);
See if character c is in the intersection of the patterns.

size_t countchars(string s, string pattern);
Count characters in s that match pattern.

string removechars(string s, in string pattern);
Return string that is s with all characters removed that match pattern.

string squeeze(string s, string 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.

S1 munch(S1, S2)(ref S1 s, S2 pattern);
Finds the position pos of the first character in s that does not match pattern (in the terminology used by inPattern). Updates s = s[pos..$]. Returns the slice from the beginning of the original (before update) string up to, and excluding, pos.

Example:
string s = "123abc";
string t = munch(s, "0123456789");
assert(t == "123" && s == "abc");
t = munch(s, "0123456789");
assert(t == "" && s == "abc");
The munch function is mostly convenient for skipping certain category of characters (e.g. whitespace) when parsing strings. (In such cases, the return value is not used.)

string succ(string 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.

string tr(string str, string from, string to, string modifiers = null);
Replaces characters in str[] that are in from[] with corresponding characters in to[] and returns the resulting string.

Parameters:
string 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(string s, in bool bAllowSep = false);
[in] string 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(string 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.

Parameters:
string 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.

string[string] abbrev(string[] 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 string[] 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(string str, int tabsize = 8);
Compute column number after string if string starts in the leftmost column, which is numbered starting from 0.

string wrap(string s, int columns = 80, string firstindent = null, string 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.

Parameters:
string s | text string to be wrapped
int columns | maximum number of columns in the paragraph
string firstindent | string used to indent first line of the paragraph
string indent | string to use to indent following lines of the paragraph
int tabsize | column spacing of tabs

Returns:
The resulting paragraph.

struct ByCodeUnit(Range,Unit) if (isInputRange!(Range) && staticIndexOf!(Unqual!(Unit),char,wchar,dchar) >= 0 && staticIndexOf!(Unqual!(ElementType!(Range)),char,wchar,dchar) >= 0 && !is(Unqual!(ElementType!(Range)) == Unqual!(Unit)));

bool empty();
ElementType front();
ElementType back();
void popBack();
Range primitives

Copyright Digital Mars 2007 - 2009. | Page generated by Ddoc.


std.system

Information about the target operating system, environment, and CPU

License:
Boost License 1.0.

Authors:
Walter Bright

enum Endian;
Byte order endianness

BigEndian
big endian byte order

LittleEndian
little endian byte order

const Endian endian;
Native system endianness

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


core.thread

The thread module provides support for thread creation and management.

License:
Boost License 1.0

Authors:
Sean Kelly, Walter Bright

Source:
core/thread.d

class ThreadException: object.Exception;
Base class for thread exceptions.

class FiberException: object.Exception;
Base class for fiber exceptions.

alias btex_fptr;

class Thread;
This class encapsulates all threading functionality for the D programming language. As thread manipulation is a required facility for garbage collection, all user threads should derive from this class, and instances of this class should never be explicitly deleted. A new thread may be created using either derivation or composition, as in the following example.

Example:
 class DerivedThread : Thread
 {
     this()
     {
         super( &run );
     }

 private :
     void run()
     {
         printf( "Derived thread running.\n" );
     }
 }

 void threadFunc()
 {
     printf( "Composed thread running.\n" );
 }

 // create instances of each type
 Thread derived = new DerivedThread();
 Thread composed = new Thread( &threadFunc );

 // start both threads
 derived.start();
 composed.start();

this(void function() fn, size_t sz = 0);
Initializes a thread object which is associated with a static D function.

Parameters:
void function() fn | The thread function.
size_t sz | The stack size for this thread.

In:
fn must not be null.

this(void delegate() dg, size_t sz = 0);
Initializes a thread object which is associated with a dynamic D function.

Parameters:
void delegate() dg | The thread function.
size_t sz | The stack size for this thread.

In:
dg must not be null.

final void start();
Starts the thread and invokes the function or delegate passed upon construction.

In:
This routine may only be called once per thread instance.

Throws:
ThreadException if the thread fails to start.

final Throwable join(bool rethrow = true);
Waits for this thread to complete. If the thread terminated as the result of an unhandled exception, this exception will be rethrown.

Parameters:
bool rethrow Rethrow any unhandled exception which may have caused this thread to terminate.

Throws:
ThreadException if the operation fails. Any exception not handled by the joined thread.

Returns:
Any exception not handled by this thread if rethrow = false, null otherwise.

final string name();
Gets the user-readable label for this thread.

Returns:
The name of this thread.

final void name(string val);
Sets the user-readable label for this thread.

Parameters:
string val The new name of this thread.

final bool isDaemon();
Gets the daemon status for this thread. While the runtime will wait for all normal threads to complete before tearing down the process, daemon threads are effectively ignored and thus will not prevent the process from terminating. In effect, daemon threads will be terminated automatically by the OS when the process exits.

Returns:
true if this is a daemon thread.

final void isDaemon(bool val);
Sets the daemon status for this thread. While the runtime will wait for all normal threads to complete before tearing down the process, daemon threads are effectively ignored and thus will not prevent the process from terminating. In effect, daemon threads will be terminated automatically by the OS when the process exits.

Parameters:
bool val The new daemon status for this thread.

final bool isRunning();
Tests whether this thread is running.

Returns:
true if the thread is running, false if not.

const int PRIORITY_MIN;
The minimum scheduling priority that may be set for a thread. On systems where multiple scheduling policies are defined, this value represents the minimum valid priority for the scheduling policy of the process.

const int PRIORITY_MAX;
The maximum scheduling priority that may be set for a thread. On systems where multiple scheduling policies are defined, this value represents the minimum valid priority for the scheduling policy of the process.

final int priority();
Gets the scheduling priority for the associated thread.

Returns:
The scheduling priority of this thread.

final void priority(int val);
Sets the scheduling priority for the associated thread.

Parameters:
int val The new scheduling priority of this thread.

static void sleep(Duration val);
Suspends the calling thread for at least the supplied period. This may result in multiple OS calls if period is greater than the maximum sleep duration supported by the operating system.

Parameters:
Duration val The minimum duration the calling thread should be suspended.

In:
period must be non-negative.

Example:
 Thread.sleep( milliseconds( 50 ) );  // sleep for 50 milliseconds
 Thread.sleep( seconds( 5 ) );        // sleep for 5 seconds

static void sleep(long period);
Suspends the calling thread for at least the supplied period. This may result in multiple OS calls if period is greater than the maximum sleep duration supported by the operating system.

Parameters:
long period The minimum duration the calling thread should be suspended, in 100 nanosecond intervals.

In:
period must be non-negative.

Example:
 Thread.sleep( 500_000 );    // sleep for 50 milliseconds
 Thread.sleep( 50_000_000 ); // sleep for 5 seconds

static void yield();
Forces a context switch to occur away from the calling thread.

static Thread getThis();
Provides a reference to the calling thread.

Returns:
The thread object representing the calling thread. The result of deleting this object is undefined.

static Thread[] getAll();
Provides a list of all threads currently being tracked by the system.

Returns:
An array containing references to all threads currently being tracked by the system. The result of deleting any contained objects is undefined.

static int opApply(scope int delegate(ref Thread) dg);
Operates on all threads currently being tracked by the system. The result of deleting any Thread object is undefined.

Parameters:
int delegate(ref Thread) dg The supplied code as a delegate.

Returns:
Zero if all elemented are visited, nonzero if not.

deprecated alias findThread;

void thread_init();
Initializes the thread module. This function must be called by the garbage collector on startup and before any other thread routines are called.

bool thread_isMainThread();

Thread thread_attachThis();
Thread thread_attachByAddr(Thread.ThreadAddr addr);
Thread thread_attachByAddrB(Thread.ThreadAddr addr, void* bstack);
Registers the calling thread for use with the D Runtime. If this routine is called for a thread which is already registered, the result is undefined.

deprecated nothrow void thread_setNeedLock(bool need);
This should be handled automatically by thread_attach.

deprecated alias thread_attach;
deprecated alias thread_detach;
Renamed to be more consistent with other extern (C) routines.

void thread_detachThis();
void thread_detachByAddr(Thread.ThreadAddr addr);
Deregisters the calling thread from use with the runtime. If this routine is called for a thread which is already registered, the result is undefined.

static Thread thread_findByAddr(Thread.ThreadAddr addr);
Search the list of all threads for a thread with the given thread identifier.

Parameters:
Thread.ThreadAddr addr The thread identifier to search for.

Returns:
The thread object associated with the thread identifier, null if not found.

void thread_joinAll();
Joins all non-daemon threads that are currently running. This is done by performing successive scans through the thread list until a scan consists of only daemon threads.

nothrow bool thread_needLock();
This function is used to determine whether the the process is multi-threaded. Optimizations may only be performed on this value if the programmer can guarantee that no path from the enclosed code will start a thread.

Returns:
True if Thread.start() has been called in this process.

void thread_suspendAll();
Suspend all threads but the calling thread for "stop the world" garbage collection runs. This function may be called multiple times, and must be followed by a matching number of calls to thread_resumeAll before processing is resumed.

Throws:
ThreadException if the suspend operation fails for a running thread.

void thread_resumeAll();
Resume all threads but the calling thread for "stop the world" garbage collection runs. This function must be called once for each preceding call to thread_suspendAll before the threads are actually resumed.

In:
This routine must be preceded by a call to thread_suspendAll.

Throws:
ThreadException if the resume operation fails for a running thread.

void thread_scanAll(scanAllThreadsFn scan, void* curStackTop = null);
The main entry point for garbage collection. The supplied delegate will be passed ranges representing both stack and register values.

Parameters:
scanAllThreadsFn scan | The scanner function. It should scan from p1 through p2 - 1.
void* curStackTop | An optional pointer to the top of the calling thread's stack.

In:
This routine must be preceded by a call to thread_suspendAll.

class ThreadGroup;
This class is intended to simplify certain common programming techniques.

final Thread create(void function() fn);
Creates and starts a new Thread object that executes fn and adds it to the list of tracked threads.

Parameters:
void function() fn The thread function.

Returns:
A reference to the newly created thread.

final Thread create(void delegate() dg);
Creates and starts a new Thread object that executes dg and adds it to the list of tracked threads.

Parameters:
void delegate() dg The thread function.

Returns:
A reference to the newly created thread.

final void add(Thread t);
Add t to the list of tracked threads if it is not already being tracked.

Parameters:
Thread t The thread to add.

In:
t must not be null.

final void remove(Thread t);
Removes t from the list of tracked threads. No operation will be performed if t is not currently being tracked by this object.

Parameters:
Thread t The thread to remove.

In:
t must not be null.

final int opApply(scope int delegate(ref Thread) dg);
Operates on all threads currently tracked by this object.

final void joinAll(bool rethrow = true);
Iteratively joins all tracked threads. This function will block add, remove, and opApply until it completes.

Parameters:
bool rethrow Rethrow any unhandled exception which may have caused the current thread to terminate.

Throws:
Any exception not handled by the joined threads.

class Fiber;
This class provides a cooperative concurrency mechanism integrated with the threading and garbage collection functionality. Calling a fiber may be considered a blocking operation that returns when the fiber yields (via Fiber.yield()). Execution occurs within the context of the calling thread so synchronization is not necessary to guarantee memory visibility so long as the same thread calls the fiber each time. Please note that there is no requirement that a fiber be bound to one specific thread. Rather, fibers may be freely passed between threads so long as they are not currently executing. Like threads, a new fiber thread may be created using either derivation or composition, as in the following example.

Example:
 class DerivedFiber : Fiber
 {
     this()
     {
         super( &run );
     }

 private :
     void run()
     {
         printf( "Derived fiber running.\n" );
     }
 }

 void fiberFunc()
 {
     printf( "Composed fiber running.\n" );
     Fiber.yield();
     printf( "Composed fiber running.\n" );
 }

 // create instances of each type
 Fiber derived = new DerivedFiber();
 Fiber composed = new Fiber( &fiberFunc );

 // call both fibers once
 derived.call();
 composed.call();
 printf( "Execution returned to calling context.\n" );
 composed.call();

 // since each fiber has run to completion, each should have state TERM
 assert( derived.state == Fiber.State.TERM );
 assert( composed.state == Fiber.State.TERM );

Authors:
Based on a design by Mikola Lysenko.

this(void function() fn, size_t sz = PAGESIZE);
Initializes a fiber object which is associated with a static D function.

Parameters:
void function() fn | The thread function.
size_t sz | The stack size for this fiber.

In:
fn must not be null.

this(void delegate() dg, size_t sz = PAGESIZE);
Initializes a fiber object which is associated with a dynamic D function.

Parameters:
void delegate() dg | The thread function.
size_t sz | The stack size for this fiber.

In:
dg must not be null.

final Object call(bool rethrow = true);
Transfers execution to this fiber object. The calling context will be suspended until the fiber calls Fiber.yield() or until it terminates via an unhandled exception.

Parameters:
bool rethrow Rethrow any unhandled exception which may have caused this fiber to terminate.

In:
This fiber must be in state HOLD.

Throws:
Any exception not handled by the joined thread.

Returns:
Any exception not handled by this fiber if rethrow = false, null otherwise.

final void reset();
Resets this fiber so that it may be re-used. This routine may only be called for fibers that have terminated, as doing otherwise could result in scope-dependent functionality that is not executed. Stack-based classes, for example, may not be cleaned up properly if a fiber is reset before it has terminated.

In:
This fiber must be in state TERM.

enum State;
A fiber may occupy one of three states: HOLD, EXEC, and TERM. The HOLD state applies to any fiber that is suspended and ready to be called. The EXEC state will be set for any fiber that is currently executing. And the TERM state is set when a fiber terminates. Once a fiber terminates, it must be reset before it may be called again.

HOLD

EXEC

TERM

final const State state();
Gets the current state of this fiber.

Returns:
The state of this fiber as an enumerated value.

static void yield();
Forces a context switch to occur away from the calling fiber.

static void yieldAndThrow(Throwable t);
Forces a context switch to occur away from the calling fiber and then throws obj in the calling fiber.

Parameters:
Throwable t The object to throw.

In:
t must not be null.

static Fiber getThis();
Provides a reference to the calling fiber or null if no fiber is currently active.

Returns:
The fiber object representing the calling fiber or null if no fiber is currently active. The result of deleting this object is undefined.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


std.traits

Templates with which to extract information about types and symbols at compile time.

License:
Boost License 1.0.

Authors:
Walter Bright, Tomasz Stachowiak (isExpressionTuple), Andrei Alexandrescu, Shin Fujishiro

template ReturnType(func...) if (staticLength!(func) == 1)
Get the type of the return value from a function, a pointer to function, a delegate, a struct with an opCall, a pointer to a struct with an opCall, or a class with an opCall.

Example:
 import std.traits;
 int foo();
 ReturnType!(foo) x;   // x is declared as int

template ParameterTypeTuple(dg...) if (staticLength!(dg) == 1)
Get, as a tuple, the types of the parameters to a function, a pointer to function, a delegate, a struct with an opCall, a pointer to a struct with an opCall, or a class with an opCall.

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);

enum ParameterStorageClass;
template ParameterStorageClassTuple(func...) if (staticLength!(func) == 1)
Returns a tuple consisting of the storage classes of the parameters of a function func.

Example:
alias ParameterStorageClass STC; // shorten the enum name

void func(ref int ctx, out real result, real param)
{
}
alias ParameterStorageClassTuple!(func) pstc;
static assert(pstc.length == 3); // three parameters
static assert(pstc[0] == STC.REF);
static assert(pstc[1] == STC.OUT);
static assert(pstc[2] == STC.NONE);

NONE
SCOPE
OUT
REF
LAZY
These flags can be bitwise OR-ed together to represent complex storage class.

enum FunctionAttribute;
template functionAttributes(func...) if (staticLength!(func) == 1)
Returns the attributes attached to a function func.

Example:
alias FunctionAttribute FA; // shorten the enum name

real func(real x) pure nothrow @safe
{
    return x;
}
static assert(functionAttributes!(func) & FA.PURE);
static assert(functionAttributes!(func) & FA.SAFE);
static assert(!(functionAttributes!(func) & FA.TRUSTED)); // not @trusted

NONE
PURE
NOTHROW
REF
PROPERTY
TRUSTED
SAFE
These flags can be bitwise OR-ed together to represent complex attribute.

template isSafe(alias func)
Checks the func that is @safe or @trusted

Example:
@system int add(int a, int b) {return a+b;}
@safe int sub(int a, int b) {return a-b;}
@trusted int mul(int a, int b) {return a*b;}

bool a = isSafe!(add);
assert(a == false);
bool b = isSafe!(sub);
assert(b == true);
bool c = isSafe!(mul);
assert(c == true);

template areAllSafe(funcs...) if (funcs.length > 0)
Checks the all functions are @safe or @trusted

Example:
@system int add(int a, int b) {return a+b;}
@safe int sub(int a, int b) {return a-b;}
@trusted int mul(int a, int b) {return a*b;}

bool a = areAllSafe!(add, sub);
assert(a == false);
bool b = areAllSafe!(sub, mul);
assert(b == true);

template isUnsafe(alias func)
Checks the func that is @system

Example:
@system int add(int a, int b) {return a+b;}
@safe int sub(int a, int b) {return a-b;}
@trusted int mul(int a, int b) {return a*b;}

bool a = isUnsafe!(add);
assert(a == true);
bool b = isUnsafe!(sub);
assert(b == false);
bool c = isUnsafe!(mul);
assert(c == false);

template functionLinkage(func...) if (staticLength!(func) == 1)
Returns the calling convention of function as a string.

Example:
string a = functionLinkage!(writeln!(string, int));
assert(a == "D"); // extern(D)

auto fp = &printf;
string b = functionLinkage!(fp);
assert(b == "C"); // extern(C)

enum Variadic;
template variadicFunctionStyle(func...) if (staticLength!(func) == 1)
Determines what kind of variadic parameters function has.

Example:
void func() {}
static assert(variadicFunctionStyle!(func) == Variadic.NO);

extern(C) int printf(in char*, ...);
static assert(variadicFunctionStyle!(printf) == Variadic.C);

NO
Function is not variadic.

C
Function is a C-style variadic function.

D
Function is a D-style variadic function, which uses _argptr and _arguments.

TYPESAFE
Function is a typesafe variadic function.

template FunctionTypeOf(func...) if (staticLength!(func) == 1)
Get the function type from a callable object func.

Using builtin typeof on a property function yields the types of the property value, not of the property function itself. Still, FunctionTypeOf is able to obtain function types of properties.
class C {
    int value() @property;
}
static assert(is( typeof(C.value) == int ));
static assert(is( FunctionTypeOf!(C.value) == function ));

Note:
Do not confuse function types with function pointer types; function types are usually used for compile-time reflection purposes.

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 RepresentationTypeTuple(T...)
Get the primitive types of the fields of a struct or class, in topological order.

Example:
struct S1 { int a; float b; }
struct S2 { char[] a; union { S1 b; S1 * c; } }
alias RepresentationTypeTuple!(S2) R;
assert(R.length == 4
    && is(R[0] == char[]) && is(R[1] == int)
    && is(R[2] == float) && is(R[3] == S1*));

template hasAliasing(T...)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U* and U is not immutable;
  2. an array U[] and U is not immutable;
  3. a reference to a class or interface type C and C is not immutable.
  4. an associative array that is not immutable.
  5. a delegate.

template hasIndirections(T)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U*;
  2. an array U[];
  3. a reference to a class type C.
  4. an associative array.
  5. a delegate.

template hasUnsharedAliasing(T...)
Returns true if and only if T's representation includes at least one of the following:
  1. a raw pointer U* and U is not immutable or shared;
  2. an array U[] and U is not immutable or shared;
  3. a reference to a class type C and C is not immutable or shared.
  4. an associative array that is not immutable or shared.
  5. a delegate that is not shared.

template hasElaborateCopyConstructor(S)
True if S or any type embedded directly in the representation of S defines an elaborate copy constructor. Elaborate copy constructors are introduced by defining this(this) for a struct. (Non-struct types never have elaborate copy constructors.)

template hasElaborateAssign(S)
True if S or any type directly embedded in the representation of S defines an elaborate assignmentq. Elaborate assignments are introduced by defining opAssign(typeof(this)) or opAssign(ref typeof(this)) for a struct. (Non-struct types never have elaborate assignments.)

template hasMember(T,string name)
Yields true if and only if T is a struct or a class that defines a symbol called name.

template EnumMembers(E) if (is(E == enum))
Retrieves the members of an enumerated type enum E.

Parameters:
E An enumerated type. E may have duplicated values.

Returns:
Static tuple composed of the members of the enumerated type E. The members are arranged in the same order as declared in E.

Note:
Returned values are strictly typed with E. Thus, the following code does not work without the explicit cast:
enum E : int { a, b, c }
int[] abc = cast(int[]) [ EnumMembers!E ];
Cast is not necessary if the type of the variable is inferred. See the example below.

Examples:
Creating an array of enumerated values:
enum Sqrts : real
{
    one   = 1,
    two   = 1.41421,
    three = 1.73205,
}
auto sqrts = [ EnumMembers!Sqrts ];
assert(sqrts == [ Sqrts.one, Sqrts.two, Sqrts.three ]);
A generic function rank(v) in the following example uses this template for finding a member e in an enumerated type E.
// Returns i if e is the i-th enumerator of E.
size_t rank(E)(E e)
    if (is(E == enum))
{
    foreach (i, member; EnumMembers!E)
    {
        if (e == member)
            return i;
    }
    assert(0, "Not an enum member");
}

enum Mode
{
    read  = 1,
    write = 2,
    map   = 4,
}
assert(rank(Mode.read ) == 0);
assert(rank(Mode.write) == 1);
assert(rank(Mode.map  ) == 2);

template BaseTypeTuple(A)
Get a TypeTuple of the base class and base interfaces of this class or interface. BaseTypeTuple!(Object) returns the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }

 void main()
 {
     alias BaseTypeTuple!(B) TL;
     writeln(typeid(TL));        // prints: (A,I)
 }

template BaseClassesTuple(T)
Get a TypeTuple of all base classes of this class, in decreasing order. Interfaces are not included. BaseClassesTuple!(Object) yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }
 class C : B { }

 void main()
 {
     alias BaseClassesTuple!(C) TL;
     writeln(typeid(TL));        // prints: (B,A,Object)
 }

template InterfacesTuple(T)
Get a TypeTuple of all interfaces directly or indirectly inherited by this class or interface. Interfaces do not repeat if multiply implemented. InterfacesTuple!(Object) yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I1 { }
 interface I2 { }
 class A : I1, I2 { }
 class B : A, I1 { }
 class C : B { }

 void main()
 {
     alias InterfacesTuple!(C) TL;
     writeln(typeid(TL));        // prints: (I1, I2)
 }

template TransitiveBaseTypeTuple(T)
Get a TypeTuple of all base classes of T, in decreasing order, followed by T's interfaces. TransitiveBaseTypeTuple!(Object) yields the empty type tuple.

Example:
 import std.traits, std.typetuple, std.stdio;
 interface I { }
 class A { }
 class B : A, I { }
 class C : B { }

 void main()
 {
     alias TransitiveBaseTypeTuple!(C) TL;
     writeln(typeid(TL));        // prints: (B,A,Object,I)
 }

template MemberFunctionsTuple(C,string name) if (is(C == class) || is(C == interface))
Returns a tuple of non-static functions with the name name declared in the class or interface C. Covariant duplicates are shrunk into the most derived one.

Example:
interface I { I foo(); }
class B
{
    real foo(real v) { return v; }
}
class C : B, I
{
    override C foo() { return this; } // covariant overriding of I.foo()
}
alias MemberFunctionsTuple!(C, "foo") foos;
static assert(foos.length == 2);
static assert(__traits(isSame, foos[0], C.foo));
static assert(__traits(isSame, foos[1], B.foo));

template CommonType(T...)
Get the type that all types can be implicitly converted to. Useful e.g. in figuring out an array type from a bunch of initializing values. Returns void if passed an empty list, or if the types have no common type.

Example:
alias CommonType!(int, long, short) X;
assert(is(X == long));
alias CommonType!(int, char[], short) Y;
assert(is(Y == void));

template ImplicitConversionTargets(T)
Returns a tuple with all possible target types of an implicit conversion of a value of type T.

Important note:

The possible targets are computed more conservatively than the D 2.005 compiler does, eliminating all dangerous conversions. For example, ImplicitConversionTargets!(double) does not include float.

template isImplicitlyConvertible(From,To)
Is From implicitly convertible to To?

template isAssignable(Lhs,Rhs)
Returns true iff a value of type Rhs can be assigned to a variable of type Lhs.

Examples:
static assert(isAssignable!(long, int));
static assert(!isAssignable!(int, long));
static assert(isAssignable!(const(char)[], string));
static assert(!isAssignable!(string, char[]));

template isCovariantWith(F,G) if (is(F == function) && is(G == function))
Determines whether the function type F is covariant with G, i.e., functions of the type F can override ones of the type G.

Example:
interface I { I clone(); }
interface J { J clone(); }
class C : I
{
    override C clone()   // covariant overriding of I.clone()
    {
        return new C;
    }
}

// C.clone() can override I.clone(), indeed.
static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone)));

// C.clone() can't override J.clone(); the return type C is not implicitly
// convertible to J.
static assert(isCovariantWith!(typeof(C.clone), typeof(J.clone)));

template isIntegral(T)
Detect whether T is a built-in integral type. Types bool, char, wchar, and dchar are not considered integral.

template isFloatingPoint(T)
Detect whether T is a built-in floating point type.

template isNumeric(T)
Detect whether T is a built-in numeric type (integral or floating point).

template isUnsigned(T)
Detect whether T is a built-in unsigned numeric type.

template isSigned(T)
Detect whether T is a built-in signed numeric type.

template isSomeString(T)
Detect whether T is one of the built-in string types

template isSomeChar(T)
Detect whether T is one of the built-in character types

template isAssociativeArray(T)
Detect whether T is an associative array type

template isStaticArray(T : U[N],U,size_t N)
Detect whether type T is a static array.

template isDynamicArray(T,U = void)
Detect whether type T is a dynamic array.

template isArray(T)
Detect whether type T is an array.

template isPointer(T)
Detect whether type T is a pointer.

template pointerTarget(T : T*)
Returns the target type of a pointer.

template isIterable(T)
Returns true if T can be iterated over using a foreach loop with a single loop variable of automatically inferred type, regardless of how the foreach loop is implemented. This includes ranges, structs/classes that define opApply with a single loop variable, and builtin dynamic, static and associative arrays.

template isExpressionTuple(T...)
Tells whether the tuple T is an expression tuple.

template isTypeTuple(T...)
Detect whether tuple T is a type tuple.

template isFunctionPointer(T...) if (staticLength!(T) == 1)
Detect whether symbol or type T is a function pointer.

template isDelegate(T...) if (staticLength!(T) == 1)
Detect whether T is a delegate.

template isSomeFunction(T...) if (staticLength!(T) == 1)
Detect whether symbol or type T is a function, a function pointer or a delegate.

template isCallable(T...) if (staticLength!(T) == 1)
Detect whether T is a callable object, which can be called with the function call operator (...).

template isAbstractFunction(method...) if (staticLength!(method) == 1)
Exactly the same as the builtin traits: __traits(isAbstractFunction, method).

template Unqual(T)
Removes all qualifiers, if any, from type T.

Example:
static assert(is(Unqual!(int) == int));
static assert(is(Unqual!(const int) == int));
static assert(is(Unqual!(immutable int) == int));
static assert(is(Unqual!(shared int) == int));
static assert(is(Unqual!(shared(const int)) == int));

template ForeachType(T)
Returns the inferred type of the loop variable when a variable of type T is iterated over using a foreach loop with a single loop variable and automatically inferred return type. Note that this may not be the same as std.range.ElementType!(Range) in the case of narrow strings, or if T has both opApply and a range interface.

template OriginalType(T)
Strips off all typedefs (including enum ones) from type T.

Example:
enum E : int { a }
typedef E F;
typedef const F G;
static assert(is(OriginalType!G == const int));

template Unsigned(T)
Returns the corresponding unsigned type for T. T must be a numeric integral type, otherwise a compile-time error occurs.

template Largest(T...) if (T.length >= 1)
Returns the largest type, i.e. T such that T.sizeof is the largest. If more than one type is of the same size, the leftmost argument of these in will be returned.

template Signed(T)
Returns the corresponding signed type for T. T must be a numeric integral type, otherwise a compile-time error occurs.

template mostNegative(T)
Returns the most negative value of the numeric type T.

template mangledName(sth...) if (staticLength!(sth) == 1)
Returns the mangled name of symbol or type sth.

mangledName is the same as builtin .mangleof property, except that the correct names of property functions are obtained.
module test;
import std.traits : mangledName;

class C {
    int value() @property;
}
pragma(msg, C.value.mangleof);      // prints "i"
pragma(msg, mangledName!(C.value)); // prints "_D4test1C5valueMFNdZi"

template Select(bool condition,T,F)
Aliases itself to T if the boolean condition is true and to F otherwise.

Example:
alias Select!(size_t.sizeof == 4, int, long) Int;

A select(bool cond : true, A, B)(A a, lazy B b);
B select(bool cond : false, A, B)(lazy A a, B b);
If cond is true, returns a without evaluating b. Otherwise, returns b without evaluating a.

Copyright Digital Mars 2005 - 2009. | Page generated by Ddoc.


std.typecons

This module implements a variety of type constructors, i.e., templates that allow construction of new, useful general-purpose types.

Synopsis:
// value tuples
alias Tuple!(float, "x", float, "y", float, "z") Coord;
Coord c;
c[1] = 1;       // access by index
c.z = 1;        // access by given name
alias Tuple!(string, string) DicEntry; // names can be omitted

// Rebindable references to const and immutable objects
void bar()
{
    const w1 = new Widget, w2 = new Widget;
    w1.foo();
    // w1 = w2 would not work; can't rebind const object
    auto r = Rebindable!(const Widget)(w1);
    // invoke method as if r were a Widget object
    r.foo();
    // rebind r to refer to another object
    r = w2;
}

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu, Bartosz Milewski, Don Clugston, Shin Fujishiro

struct Unique(T);
Encapsulates unique ownership of a resource. Resource of type T is deleted at the end of the scope, unless it is transferred. The transfer can be explicit, by calling release, or implicit, when returning Unique from a function. The resource can be a polymorphic class object, in which case Unique behaves polymorphically too.

Example:

__ctor;
Constructor that takes an rvalue. It will ensure uniqueness, as long as the rvalue isn't just a view on an lvalue (e.g., a cast) Typical usage:
    Unique!(Foo) f = new Foo;

__ctor;
Constructor that takes an lvalue. It nulls its source. The nulling will ensure uniqueness as long as there are no previous aliases to the source.

Unique release();
Returns a unique rvalue. Nullifies the current contents

RefT opDot();
Forwards member access to contents

struct Tuple(Specs...);
Tuple of values, for example Tuple!(int, string) is a record that stores an int and a string. Tuple can be used to bundle values together, notably when returning multiple values from a function. If obj is a tuple, the individual members are accessible with the syntax obj[0] for the first field, obj[1] for the second, and so on.

The choice of zero-based indexing instead of one-base indexing was motivated by the ability to use value tuples with various compile-time loop constructs (e.g. type tuple iteration), all of which use zero-based indexing.

Example:
Tuple!(int, int) point;
// assign coordinates
point[0] = 5;
point[1] = 6;
// read coordinates
auto x = point[0];
auto y = point[1];
Tuple members can be named. It is legal to mix named and unnamed members. The method above is still applicable to all fields.

Example:
alias Tuple!(int, "index", string, "value") Entry;
Entry e;
e.index = 4;
e.value = "Hello";
assert(e[1] == "Hello");
assert(e[0] == 4);
Tuples with named fields are distinct types from tuples with unnamed fields, i.e. each naming imparts a separate type for the tuple. Two tuple differing in naming only are still distinct, even though they might have the same structure.

Example:
Tuple!(int, "x", int, "y") point1;
Tuple!(int, int) point2;
assert(!is(typeof(point1) == typeof(point2))); // passes

alias Types;
The type of the tuple's components.

template __ctor(U...) if (U.length == Types.length)
Constructor taking one value for each field. Each argument must be implicitly assignable to the respective element of the target.

template __ctor(U) if (isTuple!(U))
Constructor taking a compatible tuple. Each element of the source must be implicitly assignable to the respective element of the target.

template opEquals(R) if (isTuple!(R))
Comparison for equality.

bool opEquals(R rhs);
Comparison for equality.

template opCmp(R) if (isTuple!(R))
Comparison for ordering.

int opCmp(R rhs);
Comparison for ordering.

template opAssign(R) if (isTuple!(R))
Assignment from another tuple. Each element of the source must be implicitly assignable to the respective element of the target.

void opAssign(R rhs);
Assignment from another tuple. Each element of the source must be implicitly assignable to the respective element of the target.

template slice(uint from,uint to)
Takes a slice of the tuple.

Example:
Tuple!(int, string, float, double) a;
a[1] = "abc";
a[2] = 4.5;
auto s = a.slice!(1, 3);
static assert(is(typeof(s) == Tuple!(string, float)));
assert(s[0] == "abc" && s[1] == 4.5);

string toString();
Converts to string.

Tuple!(T) tuple(T...)(T args);
Returns a Tuple object instantiated and initialized according to the arguments.

Example:
auto value = tuple(5, 6.7, "hello");
assert(value[0] == 5);
assert(value[1] == 6.7);
assert(value[2] == "hello");

template isTuple(T)
Returns true if and only if T is an instance of the Tuple struct template.

template defineEnum(string name,T...)
Defines truly named enumerated values with parsing and stringizing primitives.

Example:
mixin(defineEnum!("Abc", "A", "B", 5, "C"));
is equivalent to the following code:

enum Abc { A, B = 5, C }
string enumToString(Abc v) { ... }
Abc enumFromString(string s) { ... }
The enumToString function generates the unqualified names of the enumerated values, i.e. "A", "B", and "C". The enumFromString function expects one of "A", "B", and "C", and throws an exception in any other case.

A base type can be specified for the enumeration like this:

mixin(defineEnum!("Abc", ubyte, "A", "B", "C", 255));
In this case the generated enum will have a ubyte representation.

template Rebindable(T) if (is(T == class) || is(T == interface) || isArray!(T))
Rebindable!(T) is a simple, efficient wrapper that behaves just like an object of type T, except that you can reassign it to refer to another object. For completeness, Rebindable!(T) aliases itself away to T if T is a non-const object type. However, Rebindable!(T) does not compile if T is a non-class type.

Regular const object references cannot be reassigned:

class Widget { int x; int y() const { return a; } }
const a = new Widget;
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // error! can't modify const a
However, Rebindable!(Widget) does allow reassignment, while otherwise behaving exactly like a const Widget:

auto a = Rebindable!(const Widget)(new Widget);
a.y();          // fine
a.x = 5;        // error! can't modify const a
a = new Widget; // fine
You may want to use Rebindable when you want to have mutable storage referring to const objects, for example an array of references that must be sorted in place. Rebindable does not break the soundness of D's type system and does not incur any of the risks usually associated with cast.

Rebindable!(T) rebindable(T)(T obj);
Convenience function for creating a Rebindable using automatic type inference.

Rebindable!(T) rebindable(T)(Rebindable!(T) obj);
This function simply returns the Rebindable object passed in. It's useful in generic programming cases when a given object may be either a regular class or a Rebindable.

char[] alignForSize(E...)(string[E.length] names);
Order the provided members to minimize size while preserving alignment. Returns a declaration to be mixed in.

Example:
struct Banner {
  mixin(alignForSize!(byte[6], double)(["name", "height"]));
}
Alignment is not always optimal for 80-bit reals, nor for structs declared as align(1).

BUG:
bugzilla 2029 prevents the signature from being (string[] names...), so we need to use an ugly array literal instead.

template BlackHole(Base)
BlackHole!Base is a subclass of Base which automatically implements all abstract member functions in Base as do-nothing functions. Each auto-implemented function just returns the default value of the return type without doing anything.

The name came from Class::BlackHole Perl module by Sean M. Burke.

Example:
abstract class C
{
    int m_value;
    this(int v) { m_value = v; }
    int value() @property { return m_value; }

    abstract real realValue() @property;
    abstract void doSomething();
}

void main()
{
    auto c = new BlackHole!C(42);
    writeln(c.value);     // prints "42"

    // Abstract functions are implemented as do-nothing:
    writeln(c.realValue); // prints "NaN"
    c.doSomething();      // does nothing
}

See Also:
AutoImplement, generateEmptyFunction

template WhiteHole(Base)
WhiteHole!Base is a subclass of Base which automatically implements all abstract member functions as throw-always functions. Each auto-implemented function fails with throwing an Error and does never return. Useful for trapping use of not-yet-implemented functions.

The name came from Class::WhiteHole Perl module by Michael G Schwern.

Example:
class C
{
    abstract void notYetImplemented();
}

void main()
{
    auto c = new WhiteHole!C;
    c.notYetImplemented(); // throws an Error
}

BUGS:
Nothrow functions cause program to abort in release mode because the trap is implemented with assert(0) for nothrow functions.

See Also:
AutoImplement, generateAssertTrap

class AutoImplement(Base,alias how,alias what = isAbstractFunction): Base;
AutoImplement automatically implements (by default) all abstract member functions in the class or interface Base in specified way.

Parameters:
how template which specifies how functions will be implemented/overridden.

Two arguments are passed to how: the type Base and an alias to an implemented function. Then how must return an implemented function body as a string.

The generated function body can use these keywords:
  • a0, a1, …: arguments passed to the function;
  • args: a tuple of the arguments;
  • self: an alias to the function itself;
  • parent: an alias to the overridden function (if any).

You may want to use templated property functions (instead of Implicit Template Properties) to generate complex functions:
// Prints log messages for each call to overridden functions.
string generateLogger(C, alias fun)() @property
{
    enum qname = C.stringof ~ "." ~ __traits(identifier, fun);
    string stmt;

    stmt ~= q{ struct Importer { import std.stdio; } };
    stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`;
    static if (!__traits(isAbstractFunction, fun))
    {
        static if (is(typeof(return) == void))
            stmt ~= q{ parent(args); };
        else
            stmt ~= q{
                auto r = parent(args);
                Importer.writeln("--> ", r);
                return r;
            };
    }
    return stmt;
}
what template which determines what functions should be implemented/overridden.

An argument is passed to what: an alias to a non-final member function in Base. Then what must return a boolean value. Return true to indicate that the passed function should be implemented/overridden.

// Sees if fun returns something.
template hasValue(alias fun)
{
    enum bool hasValue = !is(ReturnType!(fun) == void);
}

Note:
Generated code is inserted in the scope of std.typecons module. Thus, any useful functions outside std.typecons cannot be used in the generated code. To workaround this problem, you may import necessary things in a local struct, as done in the generateLogger() template in the above example.

BUGS:
  • Variadic arguments to constructors are not forwarded to super.
  • Deep interface inheritance causes compile error with messages like "Error: function std.typecons.AutoImplement!(Foo).AutoImplement.bar does not override any function". [Bugzilla 2525, Bugzilla 3525]
  • The parent keyword is actually a delegate to the super class' corresponding member function. [Bugzilla 2540]
  • Using alias template parameter in how and/or what may cause strange compile error. Use template tuple parameter instead to workaround this problem. [Bugzilla 4217]

template generateEmptyFunction(C,func...)
template generateAssertTrap(C,func...)
Predefined how-policies for AutoImplement. These templates are used by BlackHole and WhiteHole, respectively.

enum RefCountedAutoInitialize;
Options regarding auto-initialization of a RefCounted object (see the definition of RefCounted below).

no
Do not auto-initialize the object

yes
Auto-initialize the object

struct RefCounted(T,RefCountedAutoInitialize autoInit = RefCountedAutoInitialize.yes) if (!is(T == class));
Defines a reference-counted object containing a T value as payload. RefCounted keeps track of all references of an object, and when the reference count goes down to zero, frees the underlying store. RefCounted uses malloc and free for operation.

RefCounted is unsafe and should be used with care. No references to the payload should be escaped outside the RefCounted object.

The autoInit option makes the object ensure the store is automatically initialized. Leaving autoInit == RefCountedAutoInitialize.yes (the default option) is convenient but has the cost of a test whenever the payload is accessed. If autoInit == RefCountedAutoInitialize.no, user code must call either refCountedIsInitialized or refCountedEnsureInitialized before attempting to access the payload. Not doing so results in null pointer dereference.

Example:
// A pair of an int and a size_t - the latter being the
// reference count - will be dynamically allocated
auto rc1 = RefCounted!int(5);
assert(rc1 == 5);
// No more allocation, add just one extra reference count
auto rc2 = rc1;
// Reference semantics
rc2 = 42;
assert(rc1 == 42);
// the pair will be freed when rc1 and rc2 go out of scope

template __ctor(A...) if (A.length > 0)
Constructor that initializes the payload.

Postcondition:
refCountedIsInitialized

void opAssign(typeof(this) rhs);
void opAssign(T rhs);
Assignment operators

T refCountedPayload();
Returns a reference to the payload. If (autoInit == RefCountedAutoInitialize.yes), calls refCountedEnsureInitialized. Otherwise, just issues assert(refCountedIsInitialized). Used with alias refCountedPayload this;, so callers can just use the RefCounted object as a T.

Copyright the respective authors, 2008- | 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)

License:
Boost License 1.0.

Authors:
Walter Bright

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 staticIndexOf(T,TList...)
template staticIndexOf(alias 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 ",
          staticIndexOf!(long, TypeTuple!(int, long, double)));
    // prints: The index of long is 1
 }

alias IndexOf;
Kept for backwards compatibility

template Erase(T,TList...)
template Erase(alias 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...)
template EraseAll(alias 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...)
template Replace(alias T,U,TList...)
template Replace(T,alias U,TList...)
template Replace(alias T,alias 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...)
template ReplaceAll(alias T,U,TList...)
template ReplaceAll(T,alias U,TList...)
template ReplaceAll(alias T,alias 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)

template staticMap(alias F,T...)
Evaluates to TypeTuple!(F[T[0]], F[T[1]], ..., F[T[$ - 1]]).

Example:
alias staticMap!(Unqual, int, const int, immutable int) T;
static assert(is(T == TypeTuple!(int, int, int)));

template allSatisfy(alias F,T...)
Evaluates to F[T[0]] && F[T[1]] && ... && F[T[$ - 1]].

Example:
static assert(!allSatisfy!(isIntegral, int, double));
static assert(allSatisfy!(isIntegral, int, long));

template anySatisfy(alias F,T...)
Evaluates to F[T[0]] || F[T[1]] || ... || F[T[$ - 1]].

Example:
static assert(!anySatisfy!(isIntegral, string, double));
static assert(anySatisfy!(isIntegral, int, double));

Copyright Digital Mars 2005 - 2009. | Page generated by Ddoc.


std.uni

Simple Unicode character classification functions. For ASCII classification, see std.ctype.

References:
ASCII Table, Wikipedia, The Unicode Consortium

Trademarks:
Unicode(tm) is a trademark of Unicode, Inc.

License:
Boost License 1.0.

Authors:
Walter Bright

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 Digital Mars 2000 - 2009. | 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

License:
Boost License 1.0.

Authors:
Walter Bright

string decode(string 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.

string decodeComponent(string encodedURIComponent);
Decodes the URI string encodedURI into a UTF-8 string and returns it. All escape sequences are decoded.

string encode(string 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.

string encodeComponent(string 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.

size_t uriLength(string s);
Does string s[] start with a URL?

Returns:
-1 it does not len it does, and s[0..len] is the slice of s[] that is that URL

size_t emailLength(string s);
Does string s[] start with an email address?

Returns:
-1 it does not len it does, and s[0..i] is the slice of s[] that is that email address

References:
RFC2822

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.utf

Encode and decode UTF-8, UTF-16 and UTF-32 strings.

For Win32 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

License:
Boost License 1.0.

Authors:
Walter Bright

class UtfException: object.Exception;
Exception class that is thrown upon any errors.

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(in 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.

Throws:
UtfException if s[i] is not the start of the UTF-8 sequence.

uint stride(in wchar[] s, size_t i);
stride() returns the length of a UTF-16 sequence starting at index i in string s.

uint stride(in 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(in char[] s, size_t i);
size_t toUCSindex(in wchar[] s, size_t i);
size_t toUCSindex(in 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(in char[] s, size_t n);
size_t toUTFindex(in wchar[] s, size_t n);
size_t toUTFindex(in dchar[] s, size_t n);
Given a UCS index n into an array of characters s[], return the UTF index.

dchar decode(in char[] s, ref size_t idx);
dchar decode(in wchar[] s, ref size_t idx);
dchar decode(in 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.

size_t encode(ref char[4u] buf, dchar c);
size_t encode(ref wchar[2u] buf, dchar c);
Encodes character c into fixed-size array s. Returns the actual length of the encoded character (a number between 1 and 4 for char[4] buffers, and between 1 and 2 for wchar[2] buffers).

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[].

ubyte codeLength(C)(dchar c);
Returns the code length of c in the encoding using C as a code point. The code is returned in character count, not in bytes.

void validate(S)(in S s);
Checks to see if string is well formed or not. S can be an array of char, wchar, or dchar. Throws a UtfException if it is not. Use to check all untrusted input for correctness.

string toUTF8(in char[] s);
string toUTF8(in wchar[] s);
string toUTF8(in dchar[] s);
Encodes string s into UTF-8 and returns the encoded string.

wstring toUTF16(in char[] s);
const(wchar)* toUTF16z(in char[] s);
wstring toUTF16(in wchar[] s);
wstring toUTF16(in dchar[] s);
Encodes string s into UTF-16 and returns the encoded string. toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take an LPWSTR or LPCWSTR argument.

dstring toUTF32(in char[] s);
dstring toUTF32(in wchar[] s);
dstring toUTF32(in dchar[] s);
Encodes string s into UTF-32 and returns the encoded string.

size_t count(E)(const(E)[] s);
Returns the total number of code points encoded in a string.

The input to this function MUST be validly encoded.

Supercedes:
This function supercedes std.utf.toUCSindex().

Standards:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252

Parameters:
s the string to be counted

Copyright Digital Mars 2000 - 2010. | Page generated by Ddoc.


std.variant

This module implements a discriminated union type (a.k.a. tagged union, algebraic type). Such types are useful for type-uniform binary interfaces, interfacing with scripting languages, and comfortable exploratory programming.

Synopsis:
 Variant a; // Must assign before use, otherwise exception ensues
 // Initialize with an integer; make the type int
 Variant b = 42;
 assert(b.type == typeid(int));
 // Peek at the value
 assert(b.peek!(int) !is null && *b.peek!(int) == 42);
 // Automatically convert per language rules
 auto x = b.get!(real);
 // Assign any other type, including other variants
 a = b;
 a = 3.14;
 assert(a.type == typeid(double));
 // Implicit conversions work just as with built-in types
 assert(a > b);
 // Check for convertibility
 assert(!a.convertsTo!(int)); // double not convertible to int
 // Strings and all other arrays are supported
 a = "now I'm a string";
 assert(a == "now I'm a string");
 a = new int[42]; // can also assign arrays
 assert(a.length == 42);
 a[5] = 7;
 assert(a[5] == 7);
 // Can also assign class values
 class Foo {}
 auto foo = new Foo;
 a = foo;
 assert(*a.peek!(Foo) == foo); // and full type information is preserved

Credits:
Reviewed by Brad Roberts. Daniel Keep provided a detailed code review prompting the following improvements: (1) better support for arrays; (2) support for associative arrays; (3) friendlier behavior towards the garbage collector.

License:
Boost License 1.0.

Authors:
Andrei Alexandrescu

struct VariantN(size_t maxDataSize,AllowedTypesX...);
VariantN is a back-end type seldom used directly by user code. Two commonly-used types using VariantN as back-end are:

  1. Algebraic: A closed discriminated union with a limited type universe (e.g., Algebraic!(int, double, string) only accepts these three types and rejects anything else).
  2. Variant: An open discriminated union allowing an unbounded set of types. The restriction is that the size of the stored type cannot be larger than the largest built-in type. This means that Variant can accommodate all primitive types and all user-defined types except for large structs.

Both Algebraic and Variant share VariantN's interface. (See their respective documentations below.)

VariantN is a discriminated union type parameterized with the largest size of the types stored (maxDataSize) and with the list of allowed types (AllowedTypes). If the list is empty, then any type up of size up to maxDataSize (rounded up for alignment) can be stored in a VariantN object.

template allowed(T)
Tells whether a type T is statically allowed for storage inside a VariantN object by looking T up in AllowedTypes. If AllowedTypes is empty, all types of size up to maxSize are allowed.

template __ctor(T)
Constructs a VariantN value given an argument of a generic type. Statically rejects disallowed types.

template opAssign(T)
Assigns a VariantN from a generic argument. Statically rejects disallowed types.

VariantN opAssign(T rhs);
Assigns a VariantN from a generic argument. Statically rejects disallowed types.

const bool hasValue();
Returns true if and only if the VariantN object holds a valid value (has been initialized with, or assigned from, a valid value).

Example:
 Variant a;
 assert(!a.hasValue);
 Variant b;
 a = b;
 assert(!a.hasValue); // still no value
 a = 5;
 assert(a.hasValue);

template peek(T)
If the VariantN object holds a value of the exact type T, returns a pointer to that value. Otherwise, returns null. In cases where T is statically disallowed, peek will not compile.

Example:
 Variant a = 5;
 auto b = a.peek!(int);
 assert(b !is null);
 *b = 6;
 assert(a == 6);

T* peek();
If the VariantN object holds a value of the exact type T, returns a pointer to that value. Otherwise, returns null. In cases where T is statically disallowed, peek will not compile.

Example:
 Variant a = 5;
 auto b = a.peek!(int);
 assert(b !is null);
 *b = 6;
 assert(a == 6);

const TypeInfo type();
Returns the typeid of the currently held value.

template convertsTo(T)
Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.

bool convertsTo();
Returns true if and only if the VariantN object holds an object implicitly convertible to type U. Implicit convertibility is defined as per ImplicitConversionTargets.

template get(T) if (!is(T == const))
Returns the value stored in the VariantN object, implicitly converted to the requested type T, in fact DecayStaticToDynamicArray!(T). If an implicit conversion is not possible, throws a VariantException.

T get();
Returns the value stored in the VariantN object, implicitly converted to the requested type T, in fact DecayStaticToDynamicArray!(T). If an implicit conversion is not possible, throws a VariantException.

template coerce(T)
Returns the value stored in the VariantN object, explicitly converted (coerced) to the requested type T. If T is a string type, the value is formatted as a string. If the VariantN object is a string, a parse of the string to type T is attempted. If a conversion is not possible, throws a VariantException.

T coerce();
Returns the value stored in the VariantN object, explicitly converted (coerced) to the requested type T. If T is a string type, the value is formatted as a string. If the VariantN object is a string, a parse of the string to type T is attempted. If a conversion is not possible, throws a VariantException.

string toString();
Formats the stored value as a string.

template opEquals(T)
Comparison for equality used by the "==" and "!=" operators.

bool opEquals(T rhs);
Comparison for equality used by the "==" and "!=" operators.

template opCmp(T)
Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.

int opCmp(T rhs);
Ordering comparison used by the "<", "<=", ">", and ">=" operators. In case comparison is not sensible between the held value and rhs, an exception is thrown.

size_t toHash();
Computes the hash of the held value.

template opAdd(T)
template opSub(T)
Arithmetic between VariantN objects and numeric values. All arithmetic operations return a VariantN object typed depending on the types of both values involved. The conversion rules mimic D's built-in rules for arithmetic conversions.

VariantN opAdd(T rhs);
Arithmetic between VariantN objects and numeric values. All arithmetic operations return a VariantN object typed depending on the types of both values involved. The conversion rules mimic D's built-in rules for arithmetic conversions.

template opMul(T)
template opDiv(T)
template opMod(T)
template opAnd(T)
template opOr(T)
template opXor(T)
template opShl(T)
template opShr(T)
template opUShr(T)
template opCat(T)
template opAddAssign(T)
template opSubAssign(T)
template opMulAssign(T)
template opDivAssign(T)
template opModAssign(T)
template opAndAssign(T)
template opOrAssign(T)
template opXorAssign(T)
template opShlAssign(T)
template opShrAssign(T)
template opUShrAssign(T)
template opCatAssign(T)
ditto ditto

VariantN opMul(T rhs);
ditto ditto

template opIndex(K)
template opIndexAssign(T,N)
Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.

Example:
 auto a = Variant(new int[10]);
 a[5] = 42;
 assert(a[5] == 42);
 int[int] hash = [ 42:24 ];
 a = hash;
 assert(a[42] == 24);

Caveat:
Due to limitations in current language, read-modify-write operations op= will not work properly:

 Variant a = new int[10];
 a[5] = 42;
 a[5] += 8;
 assert(a[5] == 50); // fails, a[5] is still 42

VariantN opIndex(K i);
Array and associative array operations. If a VariantN contains an (associative) array, it can be indexed into. Otherwise, an exception is thrown.

Example:
 auto a = Variant(new int[10]);
 a[5] = 42;
 assert(a[5] == 42);
 int[int] hash = [ 42:24 ];
 a = hash;
 assert(a[42] == 24);

Caveat:
Due to limitations in current language, read-modify-write operations op= will not work properly:

 Variant a = new int[10];
 a[5] = 42;
 a[5] += 8;
 assert(a[5] == 50); // fails, a[5] is still 42

size_t length();
If the VariantN contains an (associative) array, returns the length of that array. Otherwise, throws an exception.

template opApply(Delegate) if (is(Delegate == delegate))
If the VariantN contains an array, applies dg to each element of the array in turn. Otherwise, throws an exception.

int opApply(scope Delegate dg);
If the VariantN contains an array, applies dg to each element of the array in turn. Otherwise, throws an exception.

template Algebraic(T...)
Algebraic data type restricted to a closed set of possible types. It's an alias for a VariantN with an appropriately-constructed maximum size. Algebraic is useful when it is desirable to restrict what a discriminated type could hold to the end of defining simpler and more efficient manipulation.

Future additions to Algebraic will allow compile-time checking that all possible types are handled by user code, eliminating a large class of errors.

BUGS:
Currently, Algebraic does not allow recursive data types. They will be allowed in a future iteration of the implementation.

Example:
 auto v = Algebraic!(int, double, string)(5);
 assert(v.peek!(int));
 v = 3.14;
 assert(v.peek!(double));
 // auto x = v.peek!(long); // won't compile, type long not allowed
 // v = '1'; // won't compile, type char not allowed

alias Variant;
Variant is an alias for VariantN instantiated with the largest of creal, char[], and void delegate(). This ensures that Variant is large enough to hold all of D's predefined types, including all numeric types, pointers, delegates, and class references. You may want to use VariantN directly with a different maximum size either for storing larger types, or for saving memory.

Variant[] variantArray(T...)(T args);
Returns an array of variants constructed from args.

Example:
 auto a = variantArray(1, 3.14, "Hi!");
 assert(a[1] == 3.14);
 auto b = Variant(a); // variant array as variant
 assert(b[1] == 3.14);
Code that needs functionality similar to the boxArray function in the std.boxer module can achieve it like this:

 // old
 Box[] fun(...)
 {
     ...
     return boxArray(_arguments, _argptr);
 }
 // new
 Variant[] fun(T...)(T args)
 {
     ...
     return variantArray(args);
 }
This is by design. During construction the Variant needs static type information about the type being held, so as to store a pointer to function for fast retrieval.

class VariantException: object.Exception;
Thrown in three cases:

  1. An uninitialized Variant is used in any way except assignment and hasValue;
  2. A get or coerce is attempted with an incompatible target type;
  3. A comparison between Variant objects of incompatible types is attempted.

TypeInfo source;
The source type in the conversion or comparison

TypeInfo target;
The target type in the conversion or comparison

Copyright Andrei Alexandrescu 2007 - 2009. | Page generated by Ddoc.


std.xml

Classes and functions for creating and parsing XML

The basic architecture of this module is that there are standalone functions, classes for constructing an XML document from scratch (Tag, Element and Document), and also classes for parsing a pre-existing XML file (ElementParser and DocumentParser). The parsing classes may be used to build a Document, but that is not their primary purpose. The handling capabilities of DocumentParser and ElementParser are sufficiently customizable that you can make them do pretty much whatever you want.

Example:
This example creates a DOM (Document Object Model) tree from an XML file.
import std.xml;
import std.stdio;
import std.string;

// books.xml is used in various samples throughout the Microsoft XML Core
// Services (MSXML) SDK.
//
// See http://msdn2.microsoft.com/en-us/library/ms762271(VS.85).aspx

void main()
{
    string s = cast(string)std.file.read("books.xml");

    // Check for well-formedness
    check(s);

    // Make a DOM tree
    auto doc = new Document(s);

    // Plain-print it
    writefln(doc);
}

Example:
This example does much the same thing, except that the file is deconstructed and reconstructed by hand. This is more work, but the techniques involved offer vastly more power.
import std.xml;
import std.stdio;
import std.string;

struct Book
{
    string id;
    string author;
    string title;
    string genre;
    string price;
    string pubDate;
    string description;
}

void main()
{
    string s = cast(string)std.file.read("books.xml");

    // Check for well-formedness
    check(s);

    // Take it apart
    Book[] books;

    auto xml = new DocumentParser(s);
    xml.onStartTag["book"] = (ElementParser xml)
    {
        Book book;
        book.id = xml.tag.attr["id"];

        xml.onEndTag["author"]       = (in Element e) { book.author      = e.text; };
        xml.onEndTag["title"]        = (in Element e) { book.title       = e.text; };
        xml.onEndTag["genre"]        = (in Element e) { book.genre       = e.text; };
        xml.onEndTag["price"]        = (in Element e) { book.price       = e.text; };
        xml.onEndTag["publish-date"] = (in Element e) { book.pubDate     = e.text; };
        xml.onEndTag["description"]  = (in Element e) { book.description = e.text; };

        xml.parse();

        books ~= book;
    };
    xml.parse();

    // Put it back together again;
    auto doc = new Document(new Tag("catalog"));
    foreach(book;books)
    {
        auto element = new Element("book");
        element.tag.attr["id"] = book.id;

        element ~= new Element("author",      book.author);
        element ~= new Element("title",       book.title);
        element ~= new Element("genre",       book.genre);
        element ~= new Element("price",       book.price);
        element ~= new Element("publish-date",book.pubDate);
        element ~= new Element("description", book.description);

        doc ~= element;
    }

    // Pretty-print it
    writefln(join(doc.pretty(3),"\n"));
}

License:
Boost License 1.0.

Authors:
Janice Caron

bool isChar(dchar c);
Returns true if the character is a character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isSpace(dchar c);
Returns true if the character is whitespace according to the XML standard

Only the following characters are considered whitespace in XML - space, tab, carriage return and linefeed

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isDigit(dchar c);
Returns true if the character is a digit according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isLetter(dchar c);
Returns true if the character is a letter according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isIdeographic(dchar c);
Returns true if the character is an ideographic character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isBaseChar(dchar c);
Returns true if the character is a base character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isCombiningChar(dchar c);
Returns true if the character is a combining character according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

bool isExtender(dchar c);
Returns true if the character is an extender according to the XML standard

Standards:
XML 1.0

Parameters:
dchar c the character to be tested

S encode(S)(S s);
Encodes a string by replacing all characters which need to be escaped with appropriate predefined XML entities.

encode() escapes certain characters (ampersand, quote, apostrophe, less-than and greater-than), and similarly, decode() unescapes them. These functions are provided for convenience only. You do not need to use them when using the std.xml classes, because then all the encoding and decoding will be done for you automatically.

If the string is not modified, the original will be returned.

Standards:
XML 1.0

Parameters:
s The string to be encoded

Returns:
The encoded string

Examples:
 writefln(encode("a > b")); // writes "a &gt; b"

enum DecodeMode;
Mode to use for decoding.

NONE
Do not decode
LOOSE
Decode, but ignore errors
STRICT
Decode, and throw exception on error

string decode(string s, DecodeMode mode = (DecodeMode).LOOSE);
Decodes a string by unescaping all predefined XML entities.

encode() escapes certain characters (ampersand, quote, apostrophe, less-than and greater-than), and similarly, decode() unescapes them. These functions are provided for convenience only. You do not need to use them when using the std.xml classes, because then all the encoding and decoding will be done for you automatically.

This function decodes the entities &amp;, &quot;, &apos;, &lt; and &gt, as well as decimal and hexadecimal entities such as &#x20AC;

If the string does not contain an ampersand, the original will be returned.

Note that the "mode" parameter can be one of DecodeMode.NONE (do not decode), DecodeMode.LOOSE (decode, but ignore errors), or DecodeMode.STRICT (decode, and throw a DecodeException in the event of an error).

Standards:
XML 1.0

Parameters:
string s | The string to be decoded
DecodeMode mode | (optional) Mode to use for decoding. (Defaults to LOOSE).

Throws:
DecodeException if mode == DecodeMode.STRICT and decode fails

Returns:
The decoded string

Examples:
 writefln(decode("a &gt; b")); // writes "a > b"

class Document: std.xml.Element;
Class representing an XML document.

Standards:
XML 1.0

string prolog;
Contains all text which occurs before the root element. Defaults to <?xml version="1.0"?>

string epilog;
Contains all text which occurs after the root element. Defaults to the empty string

this(string s);
Constructs a Document by parsing XML text.

This function creates a complete DOM (Document Object Model) tree.

The input to this function MUST be valid XML. This is enforced by DocumentParser's in contract.

Parameters:
string s the complete XML text.

this(const(Tag) tag);
Constructs a Document from a Tag.

Parameters:
const(Tag) tag the start tag of the document.

const bool opEquals(Object o);
Compares two Documents for equality

Examples:
 Document d1,d2;
 if (d1 == d2) { }

const int opCmp(Object o);
Compares two Documents

You should rarely need to call this function. It exists so that Documents can be used as associative array keys.

Examples:
 Document d1,d2;
 if (d1 < d2) { }

const hash_t toHash();
Returns the hash of a Document

You should rarely need to call this function. It exists so that Documents can be used as associative array keys.

const string toString();
Returns the string representation of a Document. (That is, the complete XML of a document).

class Element: std.xml.Item;
Class representing an XML element.

Standards:
XML 1.0

Tag tag;
The start tag of the element

Item[] items;
The element's items

Text[] texts;
The element's text items

CData[] cdatas;
The element's CData items

Comment[] comments;
The element's comments

ProcessingInstruction[] pis;
The element's processing instructions

Element[] elements;
The element's child elements

this(string name, string interior = null);
Constructs an Element given a name and a string to be used as a Text interior.

Parameters:
string name | the name of the element.
string interior | (optional) the string interior.

Examples:
 auto element = new Element("title","Serenity")
     // constructs the element <title>Serenity</title>

this(const(Tag) tag_);
Constructs an Element from a Tag.

Parameters:
tag the start or empty tag of the element.

void opCatAssign(Text item);
Append a text item to the interior of this element

Parameters:
Text item the item you wish to append.

Examples:
 Element element;
 element ~= new Text("hello");

void opCatAssign(CData item);
Append a CData item to the interior of this element

Parameters:
CData item the item you wish to append.

Examples:
 Element element;
 element ~= new CData("hello");

void opCatAssign(Comment item);
Append a comment to the interior of this element

Parameters:
Comment item the item you wish to append.

Examples:
 Element element;
 element ~= new Comment("hello");

void opCatAssign(ProcessingInstruction item);
Append a processing instruction to the interior of this element

Parameters:
ProcessingInstruction item the item you wish to append.

Examples:
 Element element;
 element ~= new ProcessingInstruction("hello");

void opCatAssign(Element item);
Append a complete element to the interior of this element

Parameters:
Element item the item you wish to append.

Examples:
 Element element;
 Element other = new Element("br");
 element ~= other;
    // appends element representing <br />

bool opEquals(Object o);
Compares two Elements for equality

Examples:
 Element e1,e2;
 if (e1 == e2) { }

int opCmp(Object o);
Compares two Elements

You should rarely need to call this function. It exists so that Elements can be used as associative array keys.

Examples:
 Element e1,e2;
 if (e1 < e2) { }

hash_t toHash();
Returns the hash of an Element

You should rarely need to call this function. It exists so that Elements can be used as associative array keys.

const string text(DecodeMode mode = (DecodeMode).LOOSE);
Returns the decoded interior of an element.

The element is assumed to containt text only. So, for example, given XML such as "<title>Good &amp; Bad</title>", will return "Good & Bad".

Parameters:
DecodeMode mode (optional) Mode to use for decoding. (Defaults to LOOSE).

Throws:
DecodeException if decode fails

const string[] pretty(uint indent = 2);
Returns an indented string representation of this item

Parameters:
uint indent (optional) number of spaces by which to indent this element. Defaults to 2.

const string toString();
Returns the string representation of an Element

Examples:
 auto element = new Element("br");
 writefln(element.toString); // writes "<br />"

const bool isEmptyXML();
Returns false always

enum TagType;
Tag types.

START
Used for start tags
END
Used for end tags
EMPTY
Used for empty tags

class Tag;
Class representing an XML tag.

Standards:
XML 1.0

The class invariant guarantees
  • that type is a valid enum TagType value
  • that name consists of valid characters
  • that each attribute name consists of valid characters

TagType type;
Type of tag

string name;
Tag name

string[string] attr;
Associative array of attributes

this(string name, TagType type = (TagType).START);
Constructs an instance of Tag with a specified name and type

The constructor does not initialize the attributes. To initialize the attributes, you access the attr member variable.

Parameters:
string name | the Tag's name
TagType type | (optional) the Tag's type. If omitted, defaults to TagType.START.

Examples:
 auto tag = new Tag("img",Tag.EMPTY);
 tag.attr["src"] = "http://example.com/example.jpg";

const bool opEquals(Object o);
Compares two Tags for equality

You should rarely need to call this function. It exists so that Tags can be used as associative array keys.

Examples:
 Tag tag1,tag2
 if (tag1 == tag2) { }

const int opCmp(Object o);
Compares two Tags

Examples:
 Tag tag1,tag2
 if (tag1 < tag2) { }

const hash_t toHash();
Returns the hash of a Tag

You should rarely need to call this function. It exists so that Tags can be used as associative array keys.

const string toString();
Returns the string representation of a Tag

Examples:
 auto tag = new Tag("book",TagType.START);
 writefln(tag.toString); // writes "<book>"

const bool isStart();
Returns true if the Tag is a start tag

Examples:
 if (tag.isStart) { }

const bool isEnd();
Returns true if the Tag is an end tag

Examples:
 if (tag.isEnd) { }

const bool isEmpty();
Returns true if the Tag is an empty tag

Examples:
 if (tag.isEmpty) { }

class Comment: std.xml.Item;
Class representing a comment

this(string content);
Construct a comment

Parameters:
string content the body of the comment

Throws:
CommentException if the comment body is illegal (contains "--" or exactly equals "-")

Examples:
 auto item = new Comment("This is a comment");
    // constructs <!--This is a comment-->

bool opEquals(Object o);
Compares two comments for equality

Examples:
 Comment item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two comments

You should rarely need to call this function. It exists so that Comments can be used as associative array keys.

Examples:
 Comment item1,item2;
 if (item1 < item2) { }

hash_t toHash();
Returns the hash of a Comment

You should rarely need to call this function. It exists so that Comments can be used as associative array keys.

const string toString();
Returns a string representation of this comment

const bool isEmptyXML();
Returns false always

class CData: std.xml.Item;
Class representing a Character Data section

this(string content);
Construct a chraracter data section

Parameters:
string content the body of the character data segment

Throws:
CDataException if the segment body is illegal (contains "]]>")

Examples:
 auto item = new CData("<b>hello</b>");
    // constructs <![CDATA[<b>hello</b>]]>

bool opEquals(Object o);
Compares two CDatas for equality

Examples:
 CData item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two CDatas

You should rarely need to call this function. It exists so that CDatas can be used as associative array keys.

Examples:
 CData item1,item2;
 if (item1 < item2) { }

hash_t toHash();
Returns the hash of a CData

You should rarely need to call this function. It exists so that CDatas can be used as associative array keys.

const string toString();
Returns a string representation of this CData section

const bool isEmptyXML();
Returns false always

class Text: std.xml.Item;
Class representing a text (aka Parsed Character Data) section

this(string content);
Construct a text (aka PCData) section

Parameters:
string content the text. This function encodes the text before insertion, so it is safe to insert any text

Examples:
 auto Text = new CData("a < b");
    // constructs a &lt; b

bool opEquals(Object o);
Compares two text sections for equality

Examples:
 Text item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two text sections

You should rarely need to call this function. It exists so that Texts can be used as associative array keys.

Examples:
 Text item1,item2;
 if (item1 < item2) { }

hash_t toHash();
Returns the hash of a text section

You should rarely need to call this function. It exists so that Texts can be used as associative array keys.

const string toString();
Returns a string representation of this Text section

const bool isEmptyXML();
Returns true if the content is the empty string

class XMLInstruction: std.xml.Item;
Class representing an XML Instruction section

this(string content);
Construct an XML Instruction section

Parameters:
string content the body of the instruction segment

Throws:
XIException if the segment body is illegal (contains ">")

Examples:
 auto item = new XMLInstruction("ATTLIST");
    // constructs <!ATTLIST>

bool opEquals(Object o);
Compares two XML instructions for equality

Examples:
 XMLInstruction item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two XML instructions

You should rarely need to call this function. It exists so that XmlInstructions can be used as associative array keys.

Examples:
 XMLInstruction item1,item2;
 if (item1 < item2) { }

hash_t toHash();
Returns the hash of an XMLInstruction

You should rarely need to call this function. It exists so that XmlInstructions can be used as associative array keys.

const string toString();
Returns a string representation of this XmlInstruction

const bool isEmptyXML();
Returns false always

class ProcessingInstruction: std.xml.Item;
Class representing a Processing Instruction section

this(string content);
Construct a Processing Instruction section

Parameters:
string content the body of the instruction segment

Throws:
PIException if the segment body is illegal (contains "?>")

Examples:
 auto item = new ProcessingInstruction("php");
    // constructs <?php?>

bool opEquals(Object o);
Compares two processing instructions for equality

Examples:
 ProcessingInstruction item1,item2;
 if (item1 == item2) { }

int opCmp(Object o);
Compares two processing instructions

You should rarely need to call this function. It exists so that ProcessingInstructions can be used as associative array keys.

Examples:
 ProcessingInstruction item1,item2;
 if (item1 < item2) { }

hash_t toHash();
Returns the hash of a ProcessingInstruction

You should rarely need to call this function. It exists so that ProcessingInstructions can be used as associative array keys.

const string toString();
Returns a string representation of this ProcessingInstruction

const bool isEmptyXML();
Returns false always

abstract class Item;
Abstract base class for XML items

abstract bool opEquals(Object o);
Compares with another Item of same type for equality

abstract int opCmp(Object o);
Compares with another Item of same type

abstract hash_t toHash();
Returns the hash of this item

abstract const string toString();
Returns a string representation of this item

const string[] pretty(uint indent);
Returns an indented string representation of this item

Parameters:
uint indent number of spaces by which to indent child elements

abstract const bool isEmptyXML();
Returns true if the item represents empty XML text

class DocumentParser: std.xml.ElementParser;
Class for parsing an XML Document.

This is a subclass of ElementParser. Most of the useful functions are documented there.

Standards:
XML 1.0

BUGS:
Currently only supports UTF documents.

If there is an encoding attribute in the prolog, it is ignored.

this(string xmlText_);
Constructs a DocumentParser.

The input to this function MUST be valid XML. This is enforced by the function's in contract.

Parameters:
xmltext the entire XML document as text

class ElementParser;
Class for parsing an XML element.

Standards:
XML 1.0

Note that you cannot construct instances of this class directly. You can construct a DocumentParser (which is a subclass of ElementParser), but otherwise, Instances of ElementParser will be created for you by the library, and passed your way via onStartTag handlers.

const const(Tag) tag();
The Tag at the start of the element being parsed. You can read this to determine the tag's name and attributes.

void delegate(ElementParser parser)[string] onStartTag;
Register a handler which will be called whenever a start tag is encountered which matches the specified name. You can also pass null as the name, in which case the handler will be called for any unmatched start tag.

Examples:
 // Call this function whenever a <podcast> start tag is encountered
 onStartTag["podcast"] = (ElementParser xml)
 {
     // Your code here
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

 // call myEpisodeStartHandler (defined elsewhere) whenever an <episode>
 // start tag is encountered
 onStartTag["episode"] = &myEpisodeStartHandler;

 // call delegate dg for all other start tags
 onStartTag[null] = dg;
This library will supply your function with a new instance of ElementHandler, which may be used to parse inside the element whose start tag was just found, or to identify the tag attributes of the element, etc.

Note that your function will be called for both start tags and empty tags. That is, we make no distinction between <br></br> and <br/>.

void delegate(in const(Element) element)[string] onEndTag;
Register a handler which will be called whenever an end tag is encountered which matches the specified name. You can also pass null as the name, in which case the handler will be called for any unmatched end tag.

Examples:
 // Call this function whenever a </podcast> end tag is encountered
 onEndTag["podcast"] = (in Element e)
 {
     // Your code here
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

 // call myEpisodeEndHandler (defined elsewhere) whenever an </episode>
 // end tag is encountered
 onEndTag["episode"] = &myEpisodeEndHandler;

 // call delegate dg for all other end tags
 onEndTag[null] = dg;
Note that your function will be called for both start tags and empty tags. That is, we make no distinction between <br></br> and <br/>.

void onText(Handler handler);
Register a handler which will be called whenever text is encountered.

Examples:
 // Call this function whenever text is encountered
 onText = (string s)
 {
     // Your code here

     // The passed parameter s will have been decoded by the time you see
     // it, and so may contain any character.
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void onTextRaw(Handler handler);
Register an alternative handler which will be called whenever text is encountered. This differs from onText in that onText will decode the text, wheras onTextRaw will not. This allows you to make design choices, since onText will be more accurate, but slower, while onTextRaw will be faster, but less accurate. Of course, you can still call decode() within your handler, if you want, but you'd probably want to use onTextRaw only in circumstances where you know that decoding is unnecessary.

Examples:
 // Call this function whenever text is encountered
 onText = (string s)
 {
     // Your code here

     // The passed parameter s will NOT have been decoded.
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void onCData(Handler handler);
Register a handler which will be called whenever a character data segement is encountered.

Examples:
 // Call this function whenever a CData section is encountered
 onCData = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <![CDATA[
     // nor closing ]]>
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void onComment(Handler handler);
Register a handler which will be called whenever a comment is encountered.

Examples:
 // Call this function whenever a comment is encountered
 onComment = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <!-- nor
     // closing -->
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void onPI(Handler handler);
Register a handler which will be called whenever a processing instruction is encountered.

Examples:
 // Call this function whenever a processing instruction is encountered
 onPI = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <? nor
     // closing ?>
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void onXI(Handler handler);
Register a handler which will be called whenever an XML instruction is encountered.

Examples:
 // Call this function whenever an XML instruction is encountered
 // (Note: XML instructions may only occur preceeding the root tag of a
) // document.
 onPI = (string s)
 {
     // Your code here

     // The passed parameter s does not include the opening <! nor
     // closing >
     //
     // This is a a closure, so code here may reference
     // variables which are outside of this scope
 };

void parse();
Parse an XML element.

Parsing will continue until the end of the current element. Any items encountered for which a handler has been registered will invoke that handler.

Throws:
various kinds of XMLException

const string toString();
Returns that part of the element which has already been parsed

void check(string s);
Check an entire XML document for well-formedness

Parameters:
string s the document to be checked, passed as a string

Throws:
CheckException if the document is not well formed

CheckException's toString() method will yield the complete heirarchy of parse failure (the XML equivalent of a stack trace), giving the line and column number of every failure at every level.

class XMLException: object.Exception;
The base class for exceptions thrown by this module

class CommentException: std.xml.XMLException;
Thrown during Comment constructor

class CDataException: std.xml.XMLException;
Thrown during CData constructor

class XIException: std.xml.XMLException;
Thrown during XMLInstruction constructor

class PIException: std.xml.XMLException;
Thrown during ProcessingInstruction constructor

class TextException: std.xml.XMLException;
Thrown during Text constructor

class DecodeException: std.xml.XMLException;
Thrown during decode()

class InvalidTypeException: std.xml.XMLException;
Thrown if comparing with wrong type

class TagException: std.xml.XMLException;
Thrown when parsing for Tags

class CheckException: std.xml.XMLException;
Thrown during check()

CheckException err;
Parent in heirarchy

string msg;
Name of production rule which failed to parse, or specific error message

size_t line;
Line number at which parse failure occurred

size_t column;
Column number at which parse failure occurred

Copyright Janice Caron 2008 - 2009. | 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

License:
Boost License 1.0.

Authors:
Walter Bright

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

uint compressedSize;
Read Only: size of data of member in compressed form.

uint 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[string] 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.

Parameters:
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 Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.zlib

Compress/decompress data using the zlib library.

References:
Wikipedia

License:
Boost License 1.0.

Authors:
Walter Bright

class ZlibException: object.Exception;
Errors throw a ZlibException.

uint adler32(uint adler, const(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, const(void)[] buf);
Compute the CRC32 checksum of the data in buf[]. crc is the starting value when computing a cumulative checksum.

const(void)[] compress(const(void)[] srcbuf, int level);
const(void)[] compress(const(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.

const(void)[] uncompress(const(void)[] srcbuf, uint destlen = 0u, int winbits = 15);
Decompresses the data in srcbuf[].

Parameters:
uint 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().

const(void)[] compress(const(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().

Parameters:
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().

const(void)[] uncompress(const(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 Digital Mars 2000 - 2009. | Page generated by Ddoc.


std.c.fenv

C's <fenv.h>

Authors:
Walter Bright, Digital Mars, http://www.digitalmars.com

License:
Public Domain

Copyright © 1999-2010 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

Copyright © 1999-2010 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

Copyright © 1999-2010 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-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.stdarg

C's <stdarg.h>

Authors:
Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2010 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-2010 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

Copyright © 1999-2010 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

int setenv(const char*, const char*, int);
extension to ISO C standard, not available on all platforms

int unsetenv(const char*);
extension to ISO C standard, not available on all platforms

Copyright © 1999-2010 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

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.c.time

C's <time.h>

Authors:
Walter Bright, Digital Mars, www.digitalmars.com

License:
Public Domain

Copyright © 1999-2010 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-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.windows.charset

Support UTF-8 on Windows 95, 98 and ME systems.

License:
Boost License 1.0.

Authors:
Walter Bright

const(char)* toMBSz(in char[] s, uint codePage = 0);
Converts the UTF-8 string s into a null-terminated string in a Windows 8-bit character set.

Parameters:
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

string fromMBSz(immutable(char)* s, int codePage = 0);
Converts the null-terminated string s from a Windows 8-bit character set into a UTF-8 char array.

Parameters:
immutable(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 Digital Mars 2005 - 2009. | Page generated by Ddoc.


core.atomic

The atomic module provides basic support for lock-free concurrent programming.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/atomic.d

T atomicOp(string op, T, V1)(ref shared T val, V1 mod);
Performs the binary operation 'op' on val using 'mod' as the modifier.

Parameters:
val | The target variable.
mod | The modifier to apply.

Returns:
The result of the operation.

bool cas(T, V1, V2)(shared(T)* here, const V1 ifThis, const V2 writeThis);
Stores 'writeThis' to the memory referenced by 'here' if the value referenced by 'here' is equal to 'ifThis'. This operation is both lock-free and atomic.

Parameters:
here | The address of the destination variable.
writeThis | The value to store.
ifThis | The comparison value.

Returns:
true if the store occurred, false if not.

Copyright Sean Kelly 2005 - 2010. | Page generated by Ddoc.


core.bitop

This module contains a collection of bit-level operations.

License:
Boost License 1.0

Authors:
Don Clugston, Sean Kelly, Walter Bright

Source:
core/bitop.d

int bsf(uint 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(uint 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 core.bitop;

 int main()
 {
     uint v;
     int x;

     v = 0x21;
     x = bsf(v);
     printf("bsf(x%x) = %d\n", v, x);
     x = bsr(v);
     printf("bsr(x%x) = %d\n", v, x);
     return 0;
 }

Output:
bsf(x21) = 0
bsr(x21) = 5

int bt(uint* p, uint bitnum);
Tests the bit.

int btc(uint* p, uint bitnum);
Tests and complements the bit.

int btr(uint* p, uint bitnum);
Tests and resets (sets to 0) the bit.

int bts(uint* p, uint bitnum);
Tests and sets the bit.

Parameters:
uint* p a non-NULL pointer to an array of uints.
index a bit number, starting with bit 0 of p[0], and progressing. It addresses bits like the expression:
    p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))

Returns:
A non-zero value if the bit was set, and a zero if it was clear.

Example:
    import core.bitop;

    int main()
    {
        uint array[2];

        array[0] = 2;
        array[1] = 0x100;

        printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);

        printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);

        printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);

        printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
        printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);

        printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
        printf("array = [0]:x%x, [1]:x%x\n", 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.

int popcnt(uint x);
Calculates the number of set bits in a 32-bit integer.

uint bitswap(uint x);
Reverses the order of bits in a 32-bit integer.

Copyright Don Clugston 2005 - 2009. | Page generated by Ddoc.


core.cpuid

Identify the characteristics of the host CPU, providing information about cache sizes and assembly optimisation hints.

References:
Some of this information was extremely difficult to track down. Some of the documents below were found only in cached versions stored by search engines! This code relies on information found in:

  • "Intel(R) 64 and IA-32 Architectures Software Developers Manual, Volume 2A: Instruction Set Reference, A-M" (2007).
  • "AMD CPUID Specification", Advanced Micro Devices, Rev 2.28 (2008).
  • "AMD Processor Recognition Application Note For Processors Prior to AMD Family 0Fh Processors", Advanced Micro Devices, Rev 3.13 (2005).
  • "AMD Geode(TM) GX Processors Data Book", Advanced Micro Devices, Publication ID 31505E, (2005).
  • "AMD K6 Processor Code Optimisation", Advanced Micro Devices, Rev D (2000).
  • "Application note 106: Software Customization for the 6x86 Family", Cyrix Corporation, Rev 1.5 (1998)
  • http://ftp.intron.ac/pub/document/cpu/cpuid.htm
  • "Geode(TM) GX1 Processor Series Low Power Integrated X86 Solution", National Semiconductor, (2002)
  • "The VIA Isaiah Architecture", G. Glenn Henry, Centaur Technology, Inc (2008).
  • http://www.sandpile.org/ia32/cpuid.htm
  • http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html
  • "What every programmer should know about memory", Ulrich Depper, Red Hat, Inc., (2007).
  • "CPU Identification by the Windows Kernel", G. Chappell (2009). http://www.geoffchappell.com/viewer.htm?doc=studies/windows/km/cpu/cx8.htm
  • "Intel(R) Processor Identification and the CPUID Instruction, Application Note 485" (2009).

BUGS:
Currently only works on x86 and Itanium CPUs. Many processors have bugs in their microcode for the CPUID instruction, so sometimes the cache information may be incorrect.

License:
Boost License 1.0

Authors:
Don Clugston, Tomas Lindquist Olsen <tomas@famolsen.dk>

Source:
core/cpuid.d

struct CacheInfo;
Cache size and behaviour

uint size;
Size of the cache, in kilobytes, per CPU. For L1 unified (data + code) caches, this size is half the physical size. (we don't halve it for larger sizes, since normally data size is much greater than code size for critical loops).

ubyte associativity;
Number of ways of associativity, eg: 1 = direct mapped 2 = 2-way set associative 3 = 3-way set associative ubyte.max = fully associative

uint lineSize;
Number of bytes read into the cache when a cache miss occurs.

string vendor();
Returns vendor string, for display purposes only. Do NOT use this to determine features! Note that some CPUs have programmable vendorIDs.

string processor();
Returns processor string, for display purposes only

CacheInfo[5u] datacache;
The data caches. If there are fewer than 5 physical caches levels, the remaining levels are set to uint.max (== entire memory space)

bool x87onChip();
Does it have an x87 FPU on-chip?

bool mmx();
Is MMX supported?

bool sse();
Is SSE supported?

bool sse2();
Is SSE2 supported?

bool sse3();
Is SSE3 supported?

bool ssse3();
Is SSSE3 supported?

bool sse41();
Is SSE4.1 supported?

bool sse42();
Is SSE4.2 supported?

bool sse4a();
Is SSE4a supported?

bool amd3dnow();
Is AMD 3DNOW supported?

bool amd3dnowExt();
Is AMD 3DNOW Ext supported?

bool amdMmx();
Are AMD extensions to MMX supported?

bool hasFxsr();
Is fxsave/fxrstor supported?

bool hasCmov();
Is cmov supported?

bool hasRdtsc();
Is rdtsc supported?

bool hasCmpxchg8b();
Is cmpxchg8b supported?

bool hasCmpxchg16b();
Is cmpxchg8b supported?

bool hasSysEnterSysExit();
Is SYSENTER/SYSEXIT supported?

bool has3dnowPrefetch();
Is 3DNow prefetch supported?

bool hasLahfSahf();
Are LAHF and SAHF supported in 64-bit mode?

bool hasPopcnt();
Is POPCNT supported?

bool hasLzcnt();
Is LZCNT supported?

bool isX86_64();
Is this an Intel64 or AMD 64?

bool isItanium();
Is this an IA64 (Itanium) processor?

bool hyperThreading();
Is hyperthreading supported?

uint threadsPerCPU();
Returns number of threads per CPU

uint coresPerCPU();
Returns number of cores in CPU

bool preferAthlon();
Optimisation hints for assembly code. For forward compatibility, the CPU is compared against different microarchitectures. For 32-bit X86, comparisons are made against the Intel PPro/PII/PIII/PM family.

The major 32-bit x86 microarchitecture 'dynasties' have been: (1) Intel P6 (PentiumPro, PII, PIII, PM, Core, Core2). (2) AMD Athlon (K7, K8, K10). (3) Intel NetBurst (Pentium 4, Pentium D). (4) In-order Pentium (Pentium1, PMMX, Atom) Other early CPUs (Nx586, AMD K5, K6, Centaur C3, Transmeta, Cyrix, Rise) were mostly in-order. Some new processors do not fit into the existing categories: Intel Atom 230/330 (family 6, model 0x1C) is an in-order core. Centaur Isiah = VIA Nano (family 6, model F) is an out-of-order core.

Within each dynasty, the optimisation techniques are largely identical (eg, use instruction pairing for group 4). Major instruction set improvements occur within each dynasty. Does this CPU perform better on AMD K7 code than PentiumPro..Core2 code?

bool preferPentium4();
Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code?

bool preferPentium1();
Does this CPU perform better on Pentium I code than Pentium Pro code?

uint stepping;
Processor type (vendor-dependent). This should be visible ONLY for display purposes.

uint model;
Processor type (vendor-dependent). This should be visible ONLY for display purposes.

uint family;
Processor type (vendor-dependent). This should be visible ONLY for display purposes.

Copyright Don Clugston 2007 - 2009. | Page generated by Ddoc.


core.exception

The exception module defines all system-level exceptions and provides a mechanism to alter system-level error handling.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/exception.d

class RangeError: object.Error;
Thrown on a range error.

class AssertError: object.Error;
Thrown on an assert error.

class FinalizeError: object.Error;
Thrown on finalize error.

class HiddenFuncError: object.Error;
Thrown on hidden function error.

class OutOfMemoryError: object.Error;
Thrown on an out of memory error.

class SwitchError: object.Error;
Thrown on a switch error.

class UnicodeException: object.Exception;
Thrown on a unicode conversion error.

deprecated void setAssertHandler(errorHandlerType h);
Overrides the default assert hander with a user-supplied version.

Parameters:
errorHandlerType h The new assert handler. Set to null to use the default handler.

void onAssertError(string file, size_t line);
A callback for assert errors in D. The user-supplied assert handler will be called if one has been supplied, otherwise an AssertError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

void onAssertErrorMsg(string file, size_t line, string msg);
A callback for assert errors in D. The user-supplied assert handler will be called if one has been supplied, otherwise an AssertError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.
string msg | An error message supplied by the user.

void onUnittestErrorMsg(string file, size_t line, string msg);
A callback for unittest errors in D. The user-supplied unittest handler will be called if one has been supplied, otherwise the error will be written to stderr.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.
string msg | An error message supplied by the user.

void onRangeError(string file, size_t line);
A callback for array bounds errors in D. A RangeError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

Throws:
RangeError.

void onFinalizeError(ClassInfo info, Exception ex);
A callback for finalize errors in D. A FinalizeError will be thrown.

Parameters:
e The exception thrown during finalization.

Throws:
FinalizeError.

void onHiddenFuncError(Object o);
A callback for hidden function errors in D. A HiddenFuncError will be thrown.

Throws:
HiddenFuncError.

void onOutOfMemoryError();
A callback for out of memory errors in D. An OutOfMemoryError will be thrown.

Throws:
OutOfMemoryError.

void onSwitchError(string file, size_t line);
A callback for switch errors in D. A SwitchError will be thrown.

Parameters:
string file | The name of the file that signaled this error.
size_t line | The line number on which this error occurred.

Throws:
SwitchError.

void onUnicodeError(string msg, size_t idx);
A callback for unicode errors in D. A UnicodeException will be thrown.

Parameters:
string msg | Information about the error.
size_t idx | String index where this error was detected.

Throws:
UnicodeException.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.runtime

The runtime module exposes information specific to the D runtime code.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/runtime.d

struct Runtime;
This struct encapsulates all functionality related to the underlying runtime module for the calling context.

static bool initialize(ExceptionHandler dg = null);
Initializes the runtime. This call is to be used in instances where the standard program initialization process is not executed. This is most often in shared libraries or in libraries linked to a C program.

Parameters:
ExceptionHandler dg A delegate which will receive any exception thrown during the initialization process or null if such exceptions should be discarded.

Returns:
true if initialization succeeds and false if initialization fails.

static bool terminate(ExceptionHandler dg = null);
Terminates the runtime. This call is to be used in instances where the standard program termination process will not be not executed. This is most often in shared libraries or in libraries linked to a C program.

Parameters:
ExceptionHandler dg A delegate which will receive any exception thrown during the termination process or null if such exceptions should be discarded.

Returns:
true if termination succeeds and false if termination fails.

deprecated static bool isHalting();
Returns true if the runtime is halting. Under normal circumstances, this will be set between the time that normal application code has exited and before module dtors are called.

Returns:
true if the runtime is halting.

static string[] args();
Returns the arguments supplied when the process was started.

Returns:
The arguments supplied when this process was started.

static void* loadLibrary(in char[] name);
Locates a dynamic library with the supplied library name and dynamically loads it into the caller's address space. If the library contains a D runtime it will be integrated with the current runtime.

Parameters:
char[] name The name of the dynamic library to load.

Returns:
A reference to the library or null on error.

static bool unloadLibrary(void* p);
Unloads the dynamic library referenced by p. If this library contains a D runtime then any necessary finalization or cleanup of that runtime will be performed.

Parameters:
void* p A reference to the library to unload.

static void traceHandler(TraceHandler h);
Overrides the default trace mechanism with s user-supplied version. A trace represents the context from which an exception was thrown, and the trace handler will be called when this occurs. The pointer supplied to this routine indicates the base address from which tracing should occur. If the supplied pointer is null then the trace routine should determine an appropriate calling context from which to begin the trace.

Parameters:
TraceHandler h The new trace handler. Set to null to use the default handler.

static TraceHandler traceHandler();
Gets the current trace handler.

Returns:
The current trace handler or null if no trace handler is set.

static void collectHandler(CollectHandler h);
Overrides the default collect hander with a user-supplied version. This routine will be called for each resource object that is finalized in a non-deterministic manner--typically during a garbage collection cycle. If the supplied routine returns true then the object's dtor will called as normal, but if the routine returns false than the dtor will not be called. The default behavior is for all object dtors to be called.

Parameters:
CollectHandler h The new collect handler. Set to null to use the default handler.

static CollectHandler collectHandler();
Gets the current collect handler.

Returns:
The current collect handler or null if no trace handler is set.

static void moduleUnitTester(ModuleUnitTester h);
Overrides the default module unit tester with a user-supplied version. This routine will be called once on program initialization. The return value of this routine indicates to the runtime whether the tests ran without error.

Parameters:
ModuleUnitTester h The new unit tester. Set to null to use the default unit tester.

static ModuleUnitTester moduleUnitTester();
Gets the current module unit tester.

Returns:
The current module unit tester handler or null if no trace handler is set.

bool runModuleUnitTests();
This routine is called by the runtime to run module unit tests on startup. The user-supplied unit tester will be called if one has been supplied, otherwise all unit tests will be run in sequence.

Returns:
true if execution should continue after testing is complete and false if not. Default behavior is to return true.

Throwable.TraceInfo defaultTraceHandler(void* ptr = null);

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.vararg

The vararg module is intended to facilitate vararg manipulation in D. It should be interface compatible with the C module "stdarg," and the two modules may share a common implementation if possible (as is done here).

License:
Boost License 1.0

Authors:
Walter Bright, Hauke Duden

Source:
core/vararg.d

alias va_list;
The base vararg list type.

void va_start(T)(out va_list ap, ref T parmn);
This function initializes the supplied argument pointer for subsequent use by va_arg and va_end.

Parameters:
ap | The argument pointer to initialize.
paramn | The identifier of the rightmost parameter in the function parameter list.

T va_arg(T)(ref va_list ap);
This function returns the next argument in the sequence referenced by the supplied argument pointer. The argument pointer will be adjusted to point to the next arggument in the sequence.

Parameters:
ap The argument pointer.

Returns:
The next argument in the sequence. The result is undefined if ap does not point to a valid argument.

void va_end(va_list ap);
This function cleans up any resources allocated by va_start. It is currently a no-op and exists mostly for syntax compatibility with the variadric argument functions for C.

Parameters:
va_list ap The argument pointer.

void va_copy(out va_list dst, va_list src);
This function copied the argument pointer src to dst.

Parameters:
va_list src | The source pointer.
va_list dst | The destination pointer.

Copyright Digital Mars 2000 - 2009. | Page generated by Ddoc.


core.sync.barrier

The barrier module provides a primitive for synchronizing the progress of a group of threads.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/barrier.d

class Barrier;
This class represents a barrier across which threads may only travel in groups of a specific size.

this(uint limit);
Initializes a barrier object which releases threads in groups of limit in size.

Parameters:
uint limit The number of waiting threads to release in unison.

Throws:
SyncException on error.

void wait();
Wait for the pre-determined number of threads and then proceed.

Throws:
SyncException on error.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.condition

The condition module provides a primitive for synchronized condition checking.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/condition.d

class Condition;
This class represents a condition variable as concieved by C.A.R. Hoare. As per Mesa type monitors however, "signal" has been replaced with "notify" to indicate that control is not transferred to the waiter when a notification is sent.

this(Mutex m);
Initializes a condition object which is associated with the supplied mutex object.

Parameters:
Mutex m The mutex with which this condition will be associated.

Throws:
SyncException on error.

void wait();
Wait until notified.

Throws:
SyncException on error.

bool wait(Duration val);
Suspends the calling thread until a notification occurs or until the supplied time period has elapsed.

Parameters:
Duration val The time to wait.

In:
val must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

bool wait(long period);
Suspends the calling thread until a notification occurs or until the supplied time period has elapsed.

Parameters:
long period The time to wait, in 100 nanosecond intervals. This value may be adjusted to equal to the maximum wait period supported by the target platform if it is too large.

In:
period must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

void notify();
Notifies one waiter.

Throws:
SyncException on error.

void notifyAll();
Notifies all waiters.

Throws:
SyncException on error.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.config

The config module contains utility routines and configuration information specific to this package.

License:
Boost License 1.0.

Authors:
Sean Kelly

Source:
core/sync/config.d

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.exception

Define base class for synchronization exceptions.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/exception.d

class SyncException: object.Exception;
Base class for synchronization exceptions.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.mutex

The mutex module provides a primitive for maintaining mutually exclusive access.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/mutex.d

class Mutex: object.Object.Monitor;
This class represents a general purpose, recursive mutex.

this();
Initializes a mutex object.

Throws:
SyncException on error.

this(Object o);
Initializes a mutex object and sets it as the monitor for o.

In:
o must not already have a monitor.

void lock();
If this lock is not already held by the caller, the lock is acquired, then the internal counter is incremented by one.

Throws:
SyncException on error.

void unlock();
Decrements the internal lock count by one. If this brings the count to zero, the lock is released.

Throws:
SyncException on error.

bool tryLock();
If the lock is held by another caller, the method returns. Otherwise, the lock is acquired if it is not already held, and then the internal counter is incremented by one.

Throws:
SyncException on error.

Returns:
true if the lock was acquired and false if not.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.rwmutex

The read/write mutex module provides a primitive for maintaining shared read access and mutually exclusive write access.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/rwmutex.d

class ReadWriteMutex;
This class represents a mutex that allows any number of readers to enter, but when a writer enters, all other readers and writers are blocked.

Please note that this mutex is not recursive and is intended to guard access to data only. Also, no deadlock checking is in place because doing so would require dynamic memory allocation, which would reduce performance by an unacceptable amount. As a result, any attempt to recursively acquire this mutex may well deadlock the caller, particularly if a write lock is acquired while holding a read lock, or vice-versa. In practice, this should not be an issue however, because it is uncommon to call deeply into unknown code while holding a lock that simply protects data.

enum Policy;
Defines the policy used by this mutex. Currently, two policies are defined.

The first will queue writers until no readers hold the mutex, then pass the writers through one at a time. If a reader acquires the mutex while there are still writers queued, the reader will take precedence.

The second will queue readers if there are any writers queued. Writers are passed through one at a time, and once there are no writers present, all queued readers will be alerted.

Future policies may offer a more even balance between reader and writer precedence.

PREFER_READERS
Readers get preference. This may starve writers.

PREFER_WRITERS
Writers get preference. This may starve readers.

this(Policy policy = (Policy).PREFER_WRITERS);
Initializes a read/write mutex object with the supplied policy.

Parameters:
Policy policy The policy to use.

Throws:
SyncException on error.

Policy policy();
Gets the policy for the associated mutex.

Returns:
The policy used by this mutex.

Reader reader();
Gets an object representing the reader lock for the associated mutex.

Returns:
A reader sub-mutex.

Writer writer();
Gets an object representing the writer lock for the associated mutex.

Returns:
A writer sub-mutex.

class Reader: object.Object.Monitor;
This class can be considered a mutex in its own right, and is used to negotiate a read lock for the enclosing mutex.

this();
Initializes a read/write mutex reader proxy object.

void lock();
Acquires a read lock on the enclosing mutex.

void unlock();
Releases a read lock on the enclosing mutex.

bool tryLock();
Attempts to acquire a read lock on the enclosing mutex. If one can be obtained without blocking, the lock is acquired and true is returned. If not, the lock is not acquired and false is returned.

Returns:
true if the lock was acquired and false if not.

class Writer: object.Object.Monitor;
This class can be considered a mutex in its own right, and is used to negotiate a write lock for the enclosing mutex.

this();
Initializes a read/write mutex writer proxy object.

void lock();
Acquires a write lock on the enclosing mutex.

void unlock();
Releases a write lock on the enclosing mutex.

bool tryLock();
Attempts to acquire a write lock on the enclosing mutex. If one can be obtained without blocking, the lock is acquired and true is returned. If not, the lock is not acquired and false is returned.

Returns:
true if the lock was acquired and false if not.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


core.sync.semaphore

The semaphore module provides a general use semaphore for synchronization.

License:
Boost License 1.0

Authors:
Sean Kelly

Source:
core/sync/semaphore.d

class Semaphore;
This class represents a general counting semaphore as concieved by Edsger Dijkstra. As per Mesa type monitors however, "signal" has been replaced with "notify" to indicate that control is not transferred to the waiter when a notification is sent.

this(uint count = 0);
Initializes a semaphore object with the specified initial count.

Parameters:
uint count The initial count for the semaphore.

Throws:
SyncException on error.

void wait();
Wait until the current count is above zero, then atomically decrement the count by one and return.

Throws:
SyncException on error.

bool wait(Duration val);
Suspends the calling thread until the current count moves above zero or until the supplied time period has elapsed. If the count moves above zero in this interval, then atomically decrement the count by one and return true. Otherwise, return false.

Parameters:
period The time to wait.

In:
val must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

bool wait(long period);
Suspends the calling thread until the current count moves above zero or until the supplied time period has elapsed. If the count moves above zero in this interval, then atomically decrement the count by one and return true. Otherwise, return false.

Parameters:
long period The time to wait, in 100 nanosecond intervals. This value may be adjusted to equal to the maximum wait period supported by the target platform if it is too large.

In:
period must be non-negative.

Throws:
SyncException on error.

Returns:
true if notified before the timeout and false if not.

void notify();
Atomically increment the current count by one. This will notify one waiter, if there are any in the queue.

Throws:
SyncException on error.

bool tryWait();
If the current count is equal to zero, return. Otherwise, atomically decrement the count by one and return true.

Throws:
SyncException on error.

Returns:
true if the count was above zero and false if not.

Copyright Sean Kelly 2005 - 2009. | Page generated by Ddoc.


Comparison

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

D vs Other Languages

To D, or not to D. -- Willeam NerdSpeare

This table is a quick and rough list of various features of D 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 | D
Garbage Collection | Yes
Functions
Function delegates | Yes
Function overloading | Yes
Out function parameters | Yes
Nested functions | Yes
Function literals | Yes
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
Template Constraints | 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.

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


D Builtin Rationale

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:41 2010

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.

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


Programming in D for C Programmers

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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;
}

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


Programming in D for C++ Programmers

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:38 2010

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) );
}

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


The C Preprocessor vs D

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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.

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


Template Comparison

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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 | Yes: Constraints | 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

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


D Strings vs C++ Strings

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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++:

string s1 = "hello world";
string 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".dup;
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;
}

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


D Complex Types vs C++ std::complex

D Programming Language 2.0

  • Comments
  • D
  • Search
  • Downloads
  • Home
Last update Thu Jul 19 00:06:32 2007

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.

Copyright © 1999-2007 by Digital Mars, All Rights Reserved | Page generated by Ddoc. | Comments


D's Contract Programming vs C++'s

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:39 2010

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

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


Lisp vs. Java... D?

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

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


Here a Const, There a Const

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:42 2010

Here A Const, There A Const

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


Migrating D1 Code to D2

D Programming Language 2.0

  • User Forums Forum
  • D Wiki Wiki
  • D Programming Language
  • Search Search
  • Download Downloads
  • Home
Last update Wed Nov 10 12:51:43 2010

Migrating D1 Code to D2

There are many changes to the D programming language that affect migrating source code from D1 to D2. This is an outline of changes to look for and a guide to how to modify the code. See D 2.0 Enhancements for a complete list of changes to the language.

This document is incomplete.

  • Core Language
    • New Keywords
    • Global Variables
    • Static Arrays are now Value Types
    • String Literals are Immutable
  • Phobos Library

New Keywords

D2 adds the following keywords: pure nothrow shared immutable Any use of them in D1 code must be renamed. Any variable names starting with two underscores should be renamed.

Global Variables

Global variables are now, by default, stored in thread local storage. To put them back in global storage, use the __gshared storage class:

int foo = 7; // D1 code
__gshared int foo = 7; // D2 equivalent

Carefully consider whether or not those variables actually should go into thread local storage, rather than being implicitly shared among all threads.

Static Arrays are now Value Types

In D1, a static array function parameter is passed by reference, meaning a pointer to the start of the static array is passed as an argument. This means that any changes to the array contents made by the function will be visible to the function's caller. In D2, a copy of the whole static array is passed as an argument. Changes to the array contents by the function are not visible to the function's caller, as it is a separate copy.

To migrate, add the keyword ref to the parameter declaration:

void foo(int[3] array);      // D1 code
void foo(ref int[3] array);  // D2 equivalent

String Literals are Immutable

String literals in D1 have type

char[]
, but in D2 they have type
immutable(char)[]
. To migrate usually involves doing a global search replace:

from | to
char[] | string
wchar[] | wstring
dchar[] | dstring

This will take care of most of the issues. For the rest, where mutable strings are desired, there will be some work necessary.

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


Downloads

  • D 1.015 stable dmd.zip for Win32 and x86 Linux
  • D 2.0 alpha dmd.2.007.zip for Win32 and x86 Linux
  • dmc.zip (linker and utilities) for Win32
  • GDC - D Programming Language for GCC
  • Mac OS X version of GDC
  • GDC for Ubuntu Gutsy Gibbon: sudo apt-get install gdc
  • To download specific versions of dmd, see the changelog.
  • DMDScript source
  • Empire 2.01 source

    • )
    Copyright © 1999-2008 by Digital Mars, All Rights Reserved | Page generated by Ddoc. | Comments


Digital Mars - The D Programming Language

  • Comments
  • D
  • Search
  • Downloads
  • Home
Last update Sat Mar 17 02:06:19 2007

D Programming Language

"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.

D is statically typed, and compiles direct to native code. It's multiparadigm: supporting imperative, object oriented, and template metaprogramming styles. It's a member of the C syntax family, and its look and feel is very close to C++'s. For a quick feature comparison, see this comparison of D with C, C++, C# and Java.

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 currently two implementations, the Digital Mars DMD package for Win32 and x86 Linux, and the GCC D Compiler package for several platforms, including Windows and Mac OS X.

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 Japanese book D Language Perfect Guide is available.

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(char[][] args)
{
    writefln("Hello World, Reloaded");

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

    // Nested structs and classes
    struct specs
    {
        // all members automatically initialized
        int 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 int _argc;
    private char[] _argv;

public:
    this(int argc, char[] argv)	// constructor
    {
        _argc = argc;
        _argv = argv;
    }

    int argnum()
    {
        return _argc + 1;
    }

    char[] argv()
    {
        return _argv;
    }

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

Note: all D users agree that by downloading and using D, or reading the D specs, they will explicitly identify any claims to intellectual property rights with a copyright or patent notice in any posted or emailed feedback sent to Digital Mars.

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.bitarray

Scheduled for deprecation. Use std.bitmanip instead.

Copyright © 1999-2009 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.datetime

Platform-independent high precision StopWatch.

This module provide:
  • StopWatch
  • Benchmarks
  • Some helper functions

License:
Boost License 1.0.

Authors:
Kato Shoichi

struct Ticks;
System clock time.

This type maintains the most high precision ticks of system clock in each environment. (For StopWatch)

static immutable long ticksPerSec;
Ticks that is counted per 1[s].

Confirm that it is not 0, to examine whether you can use Ticks.

static immutable Ticks appOrigin;
Ticks when application begins.

long value;
Unknown value for Ticks

You can convert this value into number of seconds by dividing it by ticksPerSec.

T toSeconds(T)();
T toSeconds(T)();
[s] as integer or real number

Attention:
This method truncate the number of digits after decimal point.

alias seconds;
[s] as real number

alias sec;
[s] as integer

Ticks fromSeconds(T)(T sec);
Create Ticks from [s] as integer

T toMilliseconds(T)();
T toMilliseconds(T)();
[ms] as integer or real number

alias milliseconds;
[ms] as real number

alias msec;
[ms] as integer

static Ticks fromMilliseconds(long msec);
Create Ticks from [ms] as integer

T toMicroseconds(T)();
T toMicroseconds(T)();
[us] as integer or real number

alias microseconds;
[us] as real number

alias usec;
[us] as integer

static Ticks fromMicroseconds(long usec);
Create Ticks from [us] as integer

void opOpAssign(string op)(in Ticks t);
operator overroading "-=, +="

BUG:
This should be return "ref Ticks", but bug2460 prevents that.

Ticks opBinary(string op)(in Ticks t);
operator overroading "-, +"

const equals_t opEquals(ref const Ticks t);
operator overroading "=="

const int opCmp(ref const Ticks t);
operator overroading "<, >, <=, >="

void opOpAssign(string op, T)(T x);
operator overroading "*=, /="

Ticks opBinary(string op, T)(T x);
operator overroading "*", "/"

real opBinary(string op)(Ticks x);
operator overroading "/"

enum AutoStart;
Special type for constructor

no

yes

AutoStart autoStart;
StopWatch's AutoStart flag

struct StopWatch;
StopWatch measures time highly precise as possible.

This class uses performance counter. On Windows, This uses QueryPerformanceCounter. For Posix, This uses clock_gettime if available, gettimeofday otherwise.

But this has dispersion in accuracy by environment. It is impossible to remove this dispersion. This depends on multi task system for example overhead from change of the context switch of the thread.

Usage is here:

Example:
void foo() {
    StopWatch sw;
    static immutable N = 100;
    Ticks[N] times;
    Ticks last = Ticks.fromSeconds(0);
    foreach (i; 0..N) {
        sw.start(); // start/resume mesuring.
        foreach (Unused; 0..1000000) bar();
        sw.stop();  // stop/pause mesuring.
        // Return value of peek() after having stopped are the always same.
        writeln((i+1)*1000000, " times done, lap time: ",
                sw.peek().msec, "[ms]");
        times[i] = sw.peek() - last;
        last = sw.peek();
    }
    real sum = 0;
    // When you want to know the number of seconds of the fact,
    // you can use properties of Ticks.
    // (seconds, mseconds, useconds, interval)
    foreach (e; times) sum += e.interval;
    writeln("Average time: ", sum/N, "[s]");
}

@safe this(AutoStart autostart);
auto start with constructor

void reset();
Reset the time measurement.

void start();
Start the time measurement.

void stop();
Stop the time measurement.

const Ticks peek();
Peek Ticks of measured time.

Ticks systime();
Ticks of system time.

Ticks apptime();
Ticks when application begin running.

Ticks[lengthof!(fun)()] benchmark(fun...)(uint times);
Benchmarks code for speed assessment and comparison.

Parameters:
fun | aliases of callable objects (e.g. function names). Each should take no arguments.
times | The number of times each function is to be executed.

Returns:
An array of n uints. Element at slot i contains the number of milliseconds spent in calling the ith function times times.

Examples:
int a;
void f0() { }
void f1() { auto b = a; }
void f2() { auto b = to!(string)(a); }
auto r = benchmark!(f0, f1, f2)(10_000_000);

struct ComparingBenchmarkResult;
Return value of benchmark with two functions comparing.

immutable real point();
Evaluation value

This return the evaluation value of performance as the ratio that is compared between BaseFunc's time and TargetFunc's time. If performance is high, this returns a high value.

immutable Ticks targetTime();
The time required of the target function

immutable Ticks baseTime();
The time required of the base function

ComparingBenchmarkResult comparingBenchmark(alias baseFunc, alias targetFunc, int times = 4095)();
ComparingBenchmarkResult comparingBenchmark(alias baseFunc, alias targetFunc, int times = 4095)();
Benchmark with two functions comparing.

Parameters:
baseFunc | The function to become the base of the speed.
targetFunc | The function that wants to measure speed.
times | The number of times each function is to be executed.

Examples:
void f1() {
    // ...
}
void f2() {
    // ...
}

void main() {
    auto b = comparingBenchmark!(f1, f2, 0x80);
    writeln(b.point);
}

TemporaryValue measureTime(alias func)();
Scope base measuring time.

When a value that is returned by this function is destroyed, func will run. func is unaly function that requires Ticks.

Examples:
writeln("benchmark start!");
{
    auto mt = measureTime!((a){assert(a.seconds);});
    doSomething();
}
writeln("benchmark end!");

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.hiddenfunc

static void _d_hidden_func();
Called by the compiler generated module assert function. Builds an Assert exception and throws it.

Copyright © 1999-2008 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

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

string 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

string 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

string 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 string name();

final string value();

Record record();

class Record;
Represents a record in the database, consisting of a set of fields

uint numFields();

uint length();

Field[] fields();

Field opIndex(index_type index);

string opIndex(string fieldName);

Field getField(string fieldName);

Field findField(string fieldName);

int hasField(string fieldName);

Database database();

int opApply(int delegate(ref Field field) dg);

int opApply(int delegate(in const(immutable(char)[]) name, in const(immutable(char)[]) value) dg);

class Database;

this(string memory, uint flags);

this(immutable(char)[][] lines, uint flags);

size_type numRecords();

size_type numFields();

size_type numLines();

uint flags();

Record[] records();

Field[] fields();

uint length();

Record opIndex(index_type index);

Record[] getRecordsContainingField(string fieldName);

Record[] getRecordsContainingField(string fieldName, string fieldValue);

int opApply(int delegate(ref Record record) dg);

int opApply(int delegate(ref Field field) dg);

Copyright © 1999-2009 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.perf

Platform-independent performance measurement and timing classes.

PerformanceCounter is the main platform-independent timer class provided, covering the most typical use case, measuring elapsed wall-clock time.

The module also provides several Windows-specific timers that can be useful in specialized situations.

Synopsis:
alias PerformanceCounter.interval_t interval_t;
auto timer = new PerformanceCounter;
timer.start();
// do computation
timer.stop();
interval_t elapsedMsec = timer.milliseconds;
writefln("Time elapsed: %s msec", elapsedMsec);
In particular note that stop() must be called before querying the elapsed time.

These classes were ported to D from the STLSoft C++ libraries, which were documented in the article " Win32 Performance Measurement Options", May 2003 issue of Windows Develper Network.

Author:
Matthew Wilson

class PerformanceCounter;
A performance counter that uses the most accurate measurement APIs available on the host machine

On Linux, the implementation uses gettimeofday(). For Windows, QueryPerformanceCounter() is used if available, GetTickCount() otherwise.

alias interval_t;
The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class TickCounter;
A low-cost, low-resolution performance counter

This class provides low-resolution, but low-latency, performance monitoring.

This class is available only on Windows, but is guaranteed to be meaningful on all Windows operating systems.

alias interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class ThreadTimesCounter;
A performance counter that provides thread-specific performance timings

This class uses the operating system's performance monitoring facilities to provide timing information pertaining to the calling thread only, irrespective of the activities of other threads on the system. This class does not provide meaningful timing information on operating systems that do not provide thread-specific monitoring.

This class is available only on Windows.

alias interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

this();
Constructor

Creates an instance of the class, and caches the thread token so that measurements will be taken with respect to the thread in which the class was created.

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t kernelPeriodCount();
The elapsed count in the measurement period for kernel mode activity

This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity

const interval_t kernelSeconds();
The number of whole seconds in the measurement period for kernel mode activity

This represents the extent, in whole seconds, of the measurement period for kernel mode activity

const interval_t kernelMilliseconds();
The number of whole milliseconds in the measurement period for kernel mode activity

This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity

const interval_t kernelMicroseconds();
The number of whole microseconds in the measurement period for kernel mode activity

This represents the extent, in whole microseconds, of the measurement period for kernel mode activity

const interval_t userPeriodCount();
The elapsed count in the measurement period for user mode activity

This represents the extent, in machine-specific increments, of the measurement period for user mode activity

const interval_t userSeconds();
The number of whole seconds in the measurement period for user mode activity

This represents the extent, in whole seconds, of the measurement period for user mode activity

const interval_t userMilliseconds();
The number of whole milliseconds in the measurement period for user mode activity

This represents the extent, in whole milliseconds, of the measurement period for user mode activity

const interval_t userMicroseconds();
The number of whole microseconds in the measurement period for user mode activity

This represents the extent, in whole microseconds, of the measurement period for user mode activity

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

class ProcessTimesCounter;
A performance counter that provides process-specific performance timings

This class uses the operating system's performance monitoring facilities to provide timing information pertaining to the calling process only, irrespective of the activities of other processes on the system. This class does not provide meaningful timing information on operating systems that do not provide process-specific monitoring.

This class is available only on Windows.

alias interval_t;
The interval type

The type of the interval measurement (generally a 64-bit signed integer)

void start();
Starts measurement

Begins a measurement period

void stop();
Ends measurement

Marks the end of a measurement period. This must be called before querying the elapsed time with period_count, seconds, milliseconds, or microseconds.

The stop() method may be called multiple times without an intervening start(). Elapsed time is always measured from most recent start() to the most recent stop().

const interval_t kernelPeriodCount();
The elapsed count in the measurement period for kernel mode activity

This represents the extent, in machine-specific increments, of the measurement period for kernel mode activity

const interval_t kernelSeconds();
The number of whole seconds in the measurement period for kernel mode activity

This represents the extent, in whole seconds, of the measurement period for kernel mode activity

const interval_t kernelMilliseconds();
The number of whole milliseconds in the measurement period for kernel mode activity

This represents the extent, in whole milliseconds, of the measurement period for kernel mode activity

const interval_t kernelMicroseconds();
The number of whole microseconds in the measurement period for kernel mode activity

This represents the extent, in whole microseconds, of the measurement period for kernel mode activity

const interval_t userPeriodCount();
The elapsed count in the measurement period for user mode activity

This represents the extent, in machine-specific increments, of the measurement period for user mode activity

const interval_t userSeconds();
The number of whole seconds in the measurement period for user mode activity

This represents the extent, in whole seconds, of the measurement period for user mode activity

const interval_t userMilliseconds();
The number of whole milliseconds in the measurement period for user mode activity

This represents the extent, in whole milliseconds, of the measurement period for user mode activity

const interval_t userMicroseconds();
The number of whole microseconds in the measurement period for user mode activity

This represents the extent, in whole microseconds, of the measurement period for user mode activity

const interval_t periodCount();
The elapsed count in the measurement period

This represents the extent, in machine-specific increments, of the measurement period

const interval_t seconds();
The number of whole seconds in the measurement period

This represents the extent, in whole seconds, of the measurement period

const interval_t milliseconds();
The number of whole milliseconds in the measurement period

This represents the extent, in whole milliseconds, of the measurement period

const interval_t microseconds();
The number of whole microseconds in the measurement period

This represents the extent, in whole microseconds, of the measurement period

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


std.slist

struct SList(T);
Singly-linked list. The intent is to make it as efficient as the simplest hand-coded list. Therefore, no tricks are employed - no phantom node, no circularity, no fat iterators, just a straight list of nodes terminated by null. Therefore, SList only supports forward iteration, does not have access to its last element, and only supports adding elements to the front or after the current iterator.

SList opCall(size_t length, T value);
Builds a list of length elements, initialized with value.

SList opCall(size_t length = 0);
Build a list of length elements, initialized with T.init.

template opEquals(U)
Compares a list with an array for element-wise equality.

int opEquals(const(U)[] v);
Compares a list with an array for element-wise equality.

Iterator!(SList!(T)) begin(T)(ref SList!(T) lst);
Returns an iterator to the head of the list.

Iterator!(SList!(T)) end(T)(ref SList!(T) lst);
Returns an iterator after the end of the list (null in fact).

Ref!(T) front(T)(ref SList!(T) lst);
Returns the first element in the list. Precondition: !isEmpty(lst).

Iterator!(SList!(T)) pushFront(T,U...)(ref SList!(T) lst, U elems);
Pushes elems to the front of the list lst, and returns an iterator to the root of the list.

bool isEmpty(T)(ref SList!(T) lst);
True if and only if lst is empty.

struct Iterator(L : SList!(T),T);
List iterator. Models forward iteration.

T get(T)(Iterator!(SList!(T)) i);
Read the value pointed to by the iterator.

T set(T,U)(ref Iterator!(SList!(T)) i, U rhs);
Assign to the value pointed to by the iterator.

void next(T)(ref Iterator!(SList!(T)) i);
Increment the iterator.

void popFront(T)(ref SList!(T) lst);
Pops the element in the front of the list lst.

Iterator!(SList!(T)) insertAfter(T,U)(ref SList!(T) lst, Iterator!(SList!(T)) i, U value);
Inserts an element with value value in lst after i. Returns an iterator to the element just inserted.

void insertAfter(T,U)(ref SList!(T) lst, Iterator!(SList!(T)) i, Iterator!(U) begin, Iterator!(U) end);
Pushes a range to the front of the list lst, and returns an iterator to the last element inserted.

void insertAfter(T,U)(ref SList!(T) lst, Iterator!(SList!(T)) i, size_t n, U value);
Pushes n copies of value to the front of the list lst, and returns an iterator to the last element inserted.

Iterator!(SList!(T)) eraseAfter(T)(ref SList!(T), Iterator!(SList!(T)) i);
Erases the element after the one pointed to by i.

Iterator!(SList!(T)) eraseAfter(T)(ref SList!(T) lst, Iterator!(SList!(T)) begin, Iterator!(SList!(T)) end);
Erases the elements from the element after the one pointed to by begin, up to (and including) the one pointed to by end.

void clear(T)(ref SList!(T) lst);
Erases the elements from the element after the one pointed to by begin, up to (and including) the one pointed to by end.

void resize(T)(ref SList!(T) lst, size_t n);
void resize(T,U)(ref SList!(T) lst, size_t n, U value);
Inserts or erases elements at the front of lst such that the size becomes n.

size_t distanceLin(T)(Iterator!(T) from, Iterator!(T) to);
Computes the distance between two iterators in linear or better time.

Iterator!(T) lastLin(T)(Iterator!(T) from, Iterator!(T) to);
Computes the last valid iterator before to in linear or better time.

bool getNext(It : Iterator!(List!(int)))(It i, ref T target);
Reads the value pointed to by the iterator, and increments the iterator.

Copyright © 1999-2007 by Digital Mars, All Rights Reserved | Page generated by Ddoc.


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(scope int delegate(ref string 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(scope 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(scope int delegate(ref string 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(scope int delegate(ref Value value) dg);
@} \name Attributes @{ Construction

Copyright © 1999-2010 by Digital Mars, All Rights Reserved | Page generated by Ddoc.