Skip to content

Instantly share code, notes, and snippets.

@PetarKirov
Created February 2, 2026 00:52
Show Gist options
  • Select an option

  • Save PetarKirov/9a4f5b91c7b22c92fdf9ccd2129c0535 to your computer and use it in GitHub Desktop.

Select an option

Save PetarKirov/9a4f5b91c7b22c92fdf9ccd2129c0535 to your computer and use it in GitHub Desktop.
D Copy Constructor — Minimal Overload Set
/+
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