Review of DIP49

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Sun Feb 2 15:54:38 PST 2014



Here are a few questions and comments:

* Why is there an immutable postblit? I wonder if there are cases in 
which that's needed. Most of the time it's fine to just memcpy() the 
data - it's immutable anyway so nothing will change! In fact there is 
one use case for immutable postblit, and that's refcounting (when 
copying data the reference count must be incremented). But that would be 
increment via a pointer, which is not allowed in your proposal. (I think 
it is ok for the postblit proposal to not cover refcounting - we can 
make it built in the language.)

* The inout case looks good, but again we need to have some good 
examples on when it would be necessary.

* What happens if an object defines both the mutable and the inout 
version of postblit? I assume the mutable has priority when duplicating 
mutable object. The DIP should clarify that.

* Const postblit is spelled "this(this) const" but that's misleading 
because it's really "this(whatever1 this) whatever2" with whatever1 and 
whatever2 being arbitrary qualifiers. We should probably find a more 
descriptive syntax for that. "this(this) auto" comes to mind. We can 
even add a contextual keyword such that the compiler recognizes 
"this(this) unique" without otherwise giving "unique" any special meaning.

* My main beef is with this constructor. I'll refer to it henceforth as 
"the unique constructor".

* Qualifiers obey a hierarchy, i.e. const(T) is a supertype of both T 
and immutable(T) as shown below with ASCII art.

  const(T)
   /\
  /  \
T   immutable(T)

That imparts structure over the mixed-qualifier constructors. However, 
that structure is missing from the unique constructor; all 
mixed-qualifier constructors are heaped into one. This makes the rules 
forced for certain constructors (e.g. constructing a const(T) from a T 
should be much less restricted than constructing a T from a const(T)). 
The proposed unique constructor is not sensitive to such distinctions.

* The "unique expression" definition is quite strong and we should 
refine it and reuse in other contexts as well.

* The section "Overloading of qualified postblits" is great because it 
brings back the subtyping structure! It says: "If mutable postblit is 
defined, it is alwasy used for the copies: (a) mutable to mutable; (b) 
mutable to const". Indeed that is correct because mutable to const is a 
copy to a supertype. To respect subtyping, we should also add (c) 
immutable to const; (d) const to const; (e) immutable to immutable. That 
way we have a simple rule: "this(this) is invoked for all upcasts 
obtained by qualifiers". Wonderful!

* If we go forward with the idea above, we only need to treat the 
remaining cases of downcasts and cross-casts across the subtyping 
hierarchy:

(a) downcasts: const(T) -> T and const(T) -> immutable(T)
(b) cross-casts: immutable(T) -> T and T -> immutable(T)

* The use of subtyping above would replace the elaborate rules in 
section "Overloading of qualified postblits". In fact they seem to agree 
95% of the time. By the way there are some confusing negations e.g. "if 
mutable postblit is not defined, it will be used for the copies". I 
assume the "not" should be removed?

* So we're left with the following postblitting rules as the maximum:

struct T {
   this(this); // all upcasts including identity
   this(const this); // construct T from const(T)
   this(const this) immutable; // construct immutable(T) from const(T)
   this(immutable this); // construct T from immutable(T)
   this(this) immutable; // construct immutable(T) from T
}

Some could be missing, some could be deduced, but this is the total set.

* Consider a conversion like "this(this) immutable" which constructs an 
immutable(T) from a T. This is tricky to typecheck because fields of T 
have a mutable type when first read and immutable type after having been 
written to. That raises the question whether the entire notion of 
postblitting is too complicated for its own good. Should we leave it as 
is and go with classic C++-style copy construction in which source and 
destination are distinct objects? I think that would simplify both the 
language definition and its implementation.

* The section "Why 'const' postblit will called to copy arbitrary 
qualified object?" alludes to the subtyping relationship among 
qualifiers without stating it.



Andrei


More information about the Digitalmars-d mailing list