To maintain compatibility with older D code, many legacy features remain supported. This page describes each legacy feature that is supported, with a suggestion of how to modernize the code.
| Feature | Summary | Edition check |
|---|---|---|
| body keyword | body after a contract statement - usedo instead | 2024 |
| alias target name; syntax | usealias name = target; instead | 2024 |
| Aliasing an instance member | Usetypeof(instance).member instead | 2024 |
| Escapingscope data | scope is enforced in@safe code | 2024 |
| Assigning to struct rvalue | Disallow for structs which overload e.g.opAssign | 2024 |
| Struct/union postblit | use a copy constructor instead. |
body was a keyword used to specify a function/method's body after a contract statement:
class Foo{void bar(int i)in {assert(i >= 42); } body {/* Do something interesting */ } string method(string s)out(v) {assert(v.length == s.length); } body {/* Do something even more interesting */ }void noBody() {/* No contracts, no body */ }}
Use thedo keyword instead (introduced in v2.075.0):
void bar(int i)in {assert(i >= 42); }do {/* Look ma, no body! */ }
From the 2024 edition,AliasDeclaration only supportsalias name = target; syntax. This is easier to find the symbol identifier, particularly whentarget is a complex symbol. The target first order came from C'stypedef syntax.
E.g.alias a = instance.field;. Such an alias actually aliases a member of the instance'stype, not the instance member itself. That could be confusing. Instead, alias a member of the type.
struct Bar{ Foo f;alias v = f.v;// Error, use `typeof(f).v`}struct Foo{int v;void test(Foo that)const {alias a =this.v;// OKalias b = that.v;// Error, use `typeof(that).v` insteadassert(&ais &b);// passesassert(&b !is &that.v); }}
It has always been an error forPOD structs to assign from an rvalue.
From the 2024 edition, it is an error to discard the result of an assignment from a struct rvalue when it would callopAssign,opOpAssign,opUnary!"++", oropUnary!"--" and the struct has no pointer fields:
struct S{int i;void opAssign(S s);}S foo();void main(){ foo() = S(2);// Error, possible no-op}
Above, unlessopAssign mutates global data, the assignment inmain will have no effect and indicates a bug.
If a struct rvalue assignment is needed to mutate global state, either call the operator overload method directly or use an lvalue. Note: Calling a non-const method on a struct rvalueis allowed.