Report a bug If you spot a problem with this page, click here to create a Bugzilla issue. Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone.

Deprecated Features

Sometimes it becomes clear that a feature is just a bad idea. These are called deprecated features and once they are judged to merit removal from the language, they follow a procedure in order to allow plenty of time for users to adjust to the change.

Deprecated Features
Feature Spec Warn Dep Error Gone
Cast T[] to integral type ? N/A 2.060  2.061
Base Class Protection 2.058N/A 2.058 2.067  
Using length in index expressions ? N/A 2.041  2.061
typedef 2.057N/A 2.057 2.067  
Variable shadowing inside functions ? N/A 0.161  2.061
invariant as an alias for immutable 2.057N/A 2.057 2.064 2.066
Using * to dereference arrays ? N/A 2.057 2.067  
Removing an item from an associative array with delete? N/A 0.127 2.061 2.067
.offset property ? N/A 0.107 2.061 2.067
.size property ? N/A 0.107 0.107 2.061
Escape string literals ? N/A 2.026 2.061 2.067
Lower case 'l' suffix for integer literals ? N/A 1.054 0.174 (never)
Octal literals 2.054N/A 2.053 2.067  
Upper case 'I' suffix for imaginary literals ? N/A 0.154 2.061 (never)
HTML source files ? N/A 2.013 N/A 2.061
.typeinfo property ? N/A 0.093 2.061 2.067
C-style function pointers ? N/A 2.050 2.067 
C-style array pointers ? 2.067     
if (v; e) ? N/A 0.149 2.061 2.068
volatile 2.013N/A 2.013 2.067  
Non-final switch statements without a default case 2.054N/A 2.054 2.068  
Hiding base class functions 2.054N/A 2.054 2.068  
Windows 3.x and Windows 9x support 2.058N/A N/A N/A 2.058
.min property for floating point types N/A 2.0612.065 2.067  
Imaginary and complex types future    
Floating point NCEG operators future 2.066   
.sort and .reverse properties for arrays future2.067    
clear 2.060  2.066  2.068
delete future    
Overriding without override future 2.004   
scope for allocating classes on the stack future    
Spec
Removal from the Specification
Warn
The compiler emits a warning if the feature is used
Dep
The compiler issues an error if not compiled with the -d switch
Error
It is an error to use the feature
Gone
The feature is completely gone

Cast T[] to integral type

At some point in time you could do:

ulong u = cast(ulong)[1,2];
To get the length of the array.

Corrective Action

Use the .length property instead.

Rationale

Using a cast to get the length of an array is just confusing.

Base Class Protection

Base class protections are things like:

class A : protected B
{
    ...
}

Corrective Action

Delete the protection attribute keyword from in front of the base class and base interfaces.

Rationale

With D's module system, it doesn't seem to serve any useful purpose, and has never worked correctly.

Using length in index expressions

When used inside an indexing or slicing expression, length is rewritten to be the length of the array being sliced.

auto a = new int[5];
a = a[0..length-1];

Corrective Action

Replace length with the equivalent '$'

Rationale

The implicitly defined length variable shadows existing declarations, and is less concise than the alternative.

typedef

typedef can be used to construct a strongly-typed alias of a type.

typedef int myint;
static assert(!is(myint == int));

Corrective Action

Replace use of typedef with alias or use std.typecons.Typedef.

Rationale

typedef is not flexible enough to cover all use cases. This is better done with a library solution.

Variable shadowing inside functions

Variable shadowing is when a variable in an inner scope has the same name as a variable in an enclosing scope.

void myFun()
{
    int var;
    if (x)
    {
        int var;
        var = 3; // which var was meant?
    }
}

Corrective Action

Rename shadowing variables so they don't conflict.

Rationale

Variable shadowing can introduce hard to find bugs where the wrong variable is modified.

invariant as an alias for immutable

The invariant storage class and type modifier is an alias for immutable.

static assert(is(invariant(int) == immutable(int)));

Corrective Action

Replace all uses of invariant as a storage class or type modifier with immutable. The invariant() syntax for struct and class invariants is still supported.

Rationale

The alias is unnecessary.

Using * to dereference arrays

D array variables can be dereferenced to get the first element, much like pointers.

int[] arr = [1, 2, 3];
assert(*arr == 1);

Corrective Action

Use indexing syntax to access first member.

int[] arr = [1, 2, 3];
assert(arr[0] == 1);

Rationale

D arrays are not pointers.

Removing an item from an associative array with delete

delete can be used to remove an item from an associative array.

int[int] aa = [1 : 2];
delete aa[1];
assert(1 !in aa);

Corrective Action

Use .remove instead.

int[int] aa = [1 : 2];
aa.remove(1);
assert(1 !in aa);

Rationale

The delete syntax is confusing and conflicts with the normal delete syntax.

.offset property

The .offset property can be used to get member offset information.

struct S { int a, b; }
static assert(S.b.offset == 4);

Corrective Action

Use .offsetof instead

struct S { int a, b; }
static assert(S.b.offsetof == 4);

Rationale

The .offset syntax has been superseded by .offsetof

.size property

The .size property can be used to get type size information

struct S { int a, b; }
static assert(S.size == 8);

Corrective Action

Use .sizeof instead

struct S { int a, b; }
static assert(S.sizeof == 8);

Rationale

The .size syntax has been superseded by .sizeof

Escape string literals

Escape string literals can be used to describe characters using escape sequences.

// deprecated code
// string x = "hello" ~ \n;

Corrective Action

Put escape sequences inside a regular string literal.

string x = "hello\n";

Rationale

Escape string literals are unintuitive and unnecessary.

Lower case 'l' suffix for integer literals

Lower case 'l' is an alternative suffix to denote 64 bit integer literals.

// deprecated code
// auto x = 123l;

Corrective Action

Use the upper case 'L' suffix.

auto x = 123L;

Rationale

The lower case suffix is easily confused with the digit '1'.

Note

In lexical analysis phase, compiler can recognize lower case suffix 'l' to report better error message - for the use case such as C-to-D code translation. Thus DMD would continue to parse 'l' suffix.

Octal literals

Octal literals can be used to enter literals in base 8.

// deprecated code
// auto x = 0123;

Corrective Action

Use the std.conv.octal template.

auto x = octal!123;

Rationale

The use of a leading zero is confusing, as 0123 != 123.

Upper case 'I' suffix for imaginary literals

The 'I' suffix can be used to denote imaginary floating point values.

// deprecated code
// auto x = 1.234I;

Corrective Action

Use the lower case 'i' suffix.

auto x = 1.234i;

Rationale

The 'I' suffix is easily confused with the digit '1'.

HTML source files

The D compiler can parse html files by ignoring everything not contained in <code></code> tags.

<html>
<code>
    ... source ...
</code>
</html>

Corrective Action

Extract code to regular source files.

Rationale

This has been replaced for documentation by the introduction of ddoc

.typeinfo property

The .typeinfo property can be used to get the associated TypeInfo class.

T.typeinfo

Corrective Action

Use typeid() instead

typeid(T)

Rationale

The .typeinfo syntax has been superseded by typeid()

C-style function pointers

C-style function pointers can be used in D.

alias void(*fptr)(int, long);

Corrective Action

Replace with D-style function pointers.

alias void function(int, long) fptr;

Rationale

The D syntax is much cleaner and easier to use.

C-style array pointers

C-style array pointers can be used in D.

alias float *arrayptr[10][15];

Corrective Action

Replace with D-style array pointers.

alias float[15][10]* arrayptr;

Rationale

The D syntax is much cleaner and easier to use.

if (v; e)

This syntax can be used to declare a variable in an if statement condition.

if (v; calculateAndReturnPointer()) { ... }

Corrective Action

Replace with an auto declaration.

if (auto v = calculateAndReturnPointer()) { ... }

Rationale

The syntax is clearer with auto.

volatile

volatile can be used to mark statement, in order to prevent some compiler optimizations.

volatile
{
    ... do something involving ghared variables ...
}

Corrective Action

Convert the code to use synchronized statements instead.

Rationale

volatile statements are a misfeature.

Non-final switch statements without a default case

Switch statements can be declared without a default case, and the compiler automatically adds one.

switch(a)
{
case 1:
    break;
case 2:
    break;
// the compiler adds
// default:
//     throw new SwitchError();
}

Corrective Action

Add the default case manually.

switch(a)
{
case 1:
    break;
case 2:
    break;
default:
    assert(0);
}

Rationale

Missing default cases can hide bugs, and making the default case explicit should be mandatory.

Hiding base class functions

Declaration functions in a derived class that can be called with the same arguments as a function in a base class, but do not override that function causes the base class function to be hidden.

class A
{
    void fun(int x) {}
}
class B : A
{
    void fun(long x) {}
}

Corrective Action

Add the function to the base class, or use an alias to bring the base class overload into the derived class.

class A
{
    void fun(int x) {}
    void fun(long x) {} // this fixes it
}
class B : A
{
    void fun(long x) {}
    alias A.fun fun; // so does this
}

Rationale

This is an error that is already detected at runtime, and is being extended to compile time.

Windows 3.x and Windows 9x support

There is some code in Phobos for Windows 3.x/9x support.

Corrective Action

Upgrade Windows or switch to another supported OS.

Rationale

Supporting such outdated and rarely used OS-es isn't worth the trouble.

.min property for floating point types

Floating point types have the .min property to access the smallest value.

enum m = real.min;

Corrective Action

Replace with .min_normal

enum m = real.min_normal;

Rationale

The name min_normal is more accurate, as .min does not include denormalized floating point values.

Imaginary and complex types

D currently supports imaginary and complex versions of all floating point types.

float a = 2;
ifloat b = 4i;
cfloat c = a + b;
assert(c == 2 + 4i);

Corrective Action

Use the library types in std.complex.

Rationale

These types are too specialized to be a part of the core language.

Floating point NCEG operators

D currently supports the NCEG floating point operators (!<>=, <>, <>=, !>, !>=, !<, !<=, !<>) for comparisons involving NaNs.

Corrective Action

Use the normal operators and std.math.isNaN.

Rationale

These operators are too specialized to be a part of the core language.

.sort and .reverse properties for arrays

D arrays can be manipulated using these built-in properties.

int[] x = [2, 3, 1];
assert(x.sort == [1, 2, 3]);

Corrective Action

Use the generic functions in std.algorithm.

Rationale

These operations are better implemented in the standard library.

clear

Call an object's destructor.

auto a = new Class();
clear(a);

Corrective Action

Use object.destroy() instead.

auto a = new Class();
destroy(a);

Rationale

Due to Uniform Function Call Syntax (UFCS), clear can cause confusion with other methods of the same name, such as a clear method used to remove the contents of a container.

delete

Memory allocated on the GC heap can be freed with delete.

auto a = new Class();
delete a;

Corrective Action

Use object.destroy() to finalize the object instead.

auto a = new Class();
destroy(a);

Note that destroy does not free the allocated memory. If necessary, call core.GC.free also.

Rationale

delete makes assumptions about the type of garbage collector available that limits which implementations can be used, and can be replaced by a library solution.

Overriding without override

Virtual functions can currently override a function in a base class without the 'override' attribute.

class A
{
    void fun() {}
}
class B : A
{
    // overrides but is not marked with override
    void fun() {}
}

Corrective Action

Mark overriding functions with override

class A
{
    void fun() {}
}
class B : A
{
    override void fun() {}
}

Rationale

Making the override attribute mandatory makes it explicit, and can catch errors when a base class function is accidentally overridden.

scope for allocating classes on the stack

The scope keyword can be used to allocate class objects on the stack:

class A
{
    int x;
    this(int x) { this.x = x; }
}

void main()
{
    A obj;
    {
        scope A a = new A(1);
        obj = a;
    }
    assert(obj.x == 1);  // fails, 'a' has been destroyed
}

Corrective Action

Use std.typecons.scoped instead.

class A
{
    this(int x) { }
}
void main()
{
    auto a = scoped!A(1);
}

Rationale

scope was an unsafe feature. A reference to a scoped class could easily be returned from a function without errors, which would make using such an object undefined behavior due to the object being destroyed after exiting the scope of the function it was allocated in. To discourage it from general-use but still allow usage when needed a library solution was implemented.

Note that scope for other usages (e.g. scoped variables) is unrelated to this feature and will not be deprecated.