www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 24454] New: Disallow initialization of non-static reference

https://issues.dlang.org/show_bug.cgi?id=24454

          Issue ID: 24454
           Summary: Disallow initialization of non-static reference type
                    data members by non-immutable values or rvalues
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: qs.il.paperinik gmail.com

When a class or struct has a member of reference type (common cases: a class, a
slice, an AA, a pointer, but also a struct type with indirections), require
that the initializer be an immutable lvalue.

Otherwise, it should be an error.

Example code:
```d
class C { } // not important what’s in there

struct S
{
    static C static_c = new C();
    static const C static_const_c = static_c;
    static immutable immut_c = new immutable C();

    C c1 = new C(); // error: rvalue
    immutable C c2 = new immutable C(); // error: rvalue
    const C c3 = static_c; // error: (possibly) mutable
    immutable C c4 = immut_c; // ok: lvalue && immutable
}
```

Rationale:

Bad case `c1` is bad because default-initialized `S` instances share the same
`c1` value. This is defined behavior, but highly unexpected and
counter-intuitive for programmers coming from other languages such as Java and

This instance is mutable, meaning when declaring a `S` variable and mutating
the `c1` member, this change affects all (future) `S` values.

Bad case `c2`: Has the same issue as `c1` except the mutation part. Still, two
default-constructed `S` values have the very same `c1` object, which is
counter-intuitive.
If `C` objects are constructed by a `pure` constructor, this case is largely
not that bad. However, if `C` objects are individually constructed, such that
even with equal parameters, there are meaningful differences between instances,
this can lead to a lot of confusion.

Bad case `c3`: Here it is clear that the instance is the same one, given the
programmer understands reference types: The same static instance is used.
However, this instance is mutable, so all `S` instances initially share the
same state mutable. Making this an error avoids a foot-gun. As the example
shows, the fact that the initializer is `const` does not help. A `const` object
may (and in this example clearly does) have a mutable object underlying it.

Good case `c4`: While as with `c3`, one needs to understand reference type
semantics, the problem is minor. While all `S` instances share the same `c4`
object, which is also quite clearly the case, this object is additionally
immutable. Even in cases where a programmer mistakes this initialization for a
deep copy and incorrectly assumes `S` objects don’t share `c4`s, this
conflation is largely unproblematic.

---

The corrective action suggested by the compiler would be to move the
initialization to constructors. There, any of the above cases can be achieved,
but in particular, the case for `c1` changes meaning largely to how programmers

meaning was intended, the programmer must be more explicit about it and e.g.
define a private static variable.

It may be noteworthy that D disallows otherwise defined syntax for the mere
purpose of not confusing programmers with experience in other languages. It is
designed like that initially (e.g. operator precedence of bitwise and
comparison) and introduced breaking changes, e.g.
https://issues.dlang.org/show_bug.cgi?id=16001

--
Mar 26