Legacy Code
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 - use do instead | 2024 |
| Aliasing an instance member | Use typeof(instance).member instead | 2024 |
| Escaping scope data | scope is enforced in @safe code | 2024 |
| Assigning to struct rvalue | Disallow for structs which overload e.g. opAssign | 2024 |
| alias target first syntax | use alias name = target instead. | |
| Struct/union postblit | use a copy constructor instead. |
body keyword
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 */ } }
Corrective Action
Use the do keyword instead (introduced in v2.075.0):
void bar(int i) in { assert(i >= 42); } do { /* Look ma, no body! */ }
Aliasing an instance member
E.g. alias a = instance.field;. Such an alias actually aliases a member of the instance's type, 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; // OK alias b = that.v; // Error, use `typeof(that).v` instead assert(&a is &b); // passes assert(&b !is &that.v); } }
Assigning to struct rvalue
It has always been an error for POD 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 call opAssign, opOpAssign, opUnary!"++", or opUnary!"--" 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, unless opAssign mutates global data, the assignment in main will have no effect and indicates a bug.
Corrective Action
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 rvalue is allowed.