Created
February 2, 2026 00:52
-
-
Save PetarKirov/9a4f5b91c7b22c92fdf9ccd2129c0535 to your computer and use it in GitHub Desktop.
D Copy Constructor — Minimal Overload Set
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /+ | |
| Copy Constructor — Minimal Overload Set (15 overloads) | |
| ====================================================== | |
| Tests all 25 source × target qualifier combinations using | |
| only 3 source groups × 5 target qualifiers = 15 overloads. | |
| Target | |
| Source │ mut │ const │ immut │ shared │ sh.const │ | |
| ──────────────┼──────┼───────┼───────┼────────┼──────────┤ | |
| mutable │ G1 │ G1 │ G1 │ G1 │ G1 │ | |
| const │ G1 │ G1 │ G1 │ G1 │ G1 │ | |
| immutable │ G2 │ G2 │ G2 │ G2 │ G2 │ | |
| shared │ G4 │ G4 │ G4 │ G4 │ G4 │ | |
| shared const │ G4 │ G4 │ G4 │ G4 │ G4 │ | |
| Minimal source groups (3): | |
| G1: `const` — accepts mutable, const sources | |
| G2: `immutable` — accepts immutable (resolves G1/G4 ambiguity) | |
| G4: `shared const` — accepts shared, shared const sources | |
| Why all 5 target qualifiers are needed: | |
| - `const` target: needed to resolve ambiguity between mutable/immutable | |
| - `shared const` target: needed to resolve ambiguity between immutable/shared | |
| - Without explicit targets, overload resolution fails with ambiguity | |
| Why G2 is needed: | |
| `immutable` implicitly converts to both `const` and `shared const`. | |
| Without G2, an immutable source would match both G1 and G4 for any | |
| target qualifier, causing an ambiguity error. | |
| Why inout doesn't work: | |
| `inout` constructors interfere with specific overloads. D's overload | |
| resolution prefers `inout` in some cases, causing "creates mutable | |
| object, not immutable" errors when crossing qualifier boundaries. | |
| +/ | |
| module copy_ctor_qualifiers; | |
| import std.stdio : writeln; | |
| struct A | |
| { | |
| int* ptr; | |
| // ==================================================================== | |
| // Group 1: const source param | |
| // Accepts: mutable, const sources. | |
| // (immutable also matches, but Group 2 is more specific.) | |
| // ==================================================================== | |
| this(ref return scope const A rhs) // → mutable | |
| { | |
| writeln(" G1 const → mutable"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope const A rhs) const // → const | |
| { | |
| writeln(" G1 const → const"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope const A rhs) immutable // → immutable | |
| { | |
| writeln(" G1 const → immutable"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope const A rhs) shared // → shared | |
| { | |
| writeln(" G1 const → shared"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope const A rhs) shared const // → shared const | |
| { | |
| writeln(" G1 const → shared const"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| // ==================================================================== | |
| // Group 2: immutable source param (exact match) | |
| // Accepts: immutable sources only. | |
| // Takes priority over G1 (const) and G4 (shared const) for | |
| // immutable sources, resolving the ambiguity. | |
| // ==================================================================== | |
| this(ref return scope immutable A rhs) // → mutable | |
| { | |
| writeln(" G2 immutable → mutable"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope immutable A rhs) const // → const | |
| { | |
| writeln(" G2 immutable → const"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope immutable A rhs) immutable // → immutable | |
| { | |
| writeln(" G2 immutable → immutable"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope immutable A rhs) shared // → shared | |
| { | |
| writeln(" G2 immutable → shared"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| this(ref return scope immutable A rhs) shared const // → shared const | |
| { | |
| writeln(" G2 immutable → shared const"); | |
| ptr = rhs.ptr ? new int(*rhs.ptr) : null; | |
| } | |
| // ==================================================================== | |
| // Group 4: shared const source param | |
| // Accepts: shared and shared const sources. | |
| // (immutable also matches, but G2 is preferred.) | |
| // Cast required to strip shared before pointer dereference. | |
| // ==================================================================== | |
| this(ref return scope shared const A rhs) // → mutable | |
| { | |
| writeln(" G4 shared const → mutable"); | |
| auto p = cast(const(int)*) rhs.ptr; | |
| ptr = p ? new int(*p) : null; | |
| } | |
| this(ref return scope shared const A rhs) const // → const | |
| { | |
| writeln(" G4 shared const → const"); | |
| auto p = cast(const(int)*) rhs.ptr; | |
| ptr = p ? new int(*p) : null; | |
| } | |
| this(ref return scope shared const A rhs) immutable // → immutable | |
| { | |
| writeln(" G4 shared const → immutable"); | |
| auto p = cast(const(int)*) rhs.ptr; | |
| ptr = p ? new int(*p) : null; | |
| } | |
| this(ref return scope shared const A rhs) shared // → shared | |
| { | |
| writeln(" G4 shared const → shared"); | |
| auto p = cast(const(int)*) rhs.ptr; | |
| ptr = p ? new int(*p) : null; | |
| } | |
| this(ref return scope shared const A rhs) shared const // → shared const | |
| { | |
| writeln(" G4 shared const → shared const"); | |
| auto p = cast(const(int)*) rhs.ptr; | |
| ptr = p ? new int(*p) : null; | |
| } | |
| } | |
| void main() | |
| { | |
| writeln("╔══════════════════════════════════════════════════════════╗"); | |
| writeln("║ D Copy Constructor — Full Qualifier Combination Test ║"); | |
| writeln("╚══════════════════════════════════════════════════════════╝"); | |
| writeln(); | |
| // ----- Create one source object per qualifier ----- | |
| A m = A(new int(1)); | |
| const A c = const A(new int(2)); | |
| immutable A im = immutable A(new int(3)); | |
| shared A s = shared A(new int(4)); | |
| shared const A sc = shared const A(new int(5)); | |
| // ----- 5 × 5 matrix: every source → every target ----- | |
| writeln("── mutable source ────────────────────────────────"); | |
| { A x = m; } | |
| { const A x = m; } | |
| { immutable A x = m; } | |
| { shared A x = m; } | |
| { shared const A x = m; } | |
| writeln("── const source ──────────────────────────────────"); | |
| { A x = c; } | |
| { const A x = c; } | |
| { immutable A x = c; } | |
| { shared A x = c; } | |
| { shared const A x = c; } | |
| writeln("── immutable source ──────────────────────────────"); | |
| { A x = im; } | |
| { const A x = im; } | |
| { immutable A x = im; } | |
| { shared A x = im; } | |
| { shared const A x = im; } | |
| writeln("── shared source ─────────────────────────────────"); | |
| { A x = s; } | |
| { const A x = s; } | |
| { immutable A x = s; } | |
| { shared A x = s; } | |
| { shared const A x = s; } | |
| writeln("── shared const source ───────────────────────────"); | |
| { A x = sc; } | |
| { const A x = sc; } | |
| { immutable A x = sc; } | |
| { shared A x = sc; } | |
| { shared const A x = sc; } | |
| // ----- Deep-copy verification (non-shared) ----- | |
| writeln(); | |
| writeln("── Deep-copy verification ────────────────────────"); | |
| { | |
| A orig = A(new int(42)); | |
| A copy = orig; | |
| assert(orig.ptr !is copy.ptr, "pointers must differ"); | |
| assert(*orig.ptr == *copy.ptr, "values must match"); | |
| *copy.ptr = 99; | |
| assert(*orig.ptr == 42, "mutation must not propagate"); | |
| writeln(" mut→mut deep copy: OK"); | |
| } | |
| { | |
| immutable A orig = immutable A(new int(77)); | |
| A copy = orig; | |
| assert(orig.ptr !is copy.ptr); | |
| assert(*orig.ptr == *copy.ptr); | |
| writeln(" immut→mut deep copy: OK"); | |
| } | |
| { | |
| A orig = A(new int(55)); | |
| immutable A copy = immutable A(orig); | |
| assert(orig.ptr !is copy.ptr); | |
| assert(*orig.ptr == *copy.ptr); | |
| writeln(" mut→immut deep copy: OK"); | |
| } | |
| writeln(); | |
| writeln("╔══════════════════════════════════════════════════════════╗"); | |
| writeln("║ ✓ All 25 qualifier combinations passed. ║"); | |
| writeln("╚══════════════════════════════════════════════════════════╝"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment