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

Reply via email to