On 2010-10-29 11:59:51 -0400, Andrei Alexandrescu <[email protected]> said:

FWIW this matter is still tormenting me. It gridlocks work on ranges, algorithms, and containers.

To recap:

1. Arbitrary cost copy construction:

+ Makes value types easy to define: just hook the copying code into this(this)
+ Is familiar to programmers coming from C++
+ If it fails, fails early, not surprisingly during a later operation
- Creates inefficiencies for innocuous-looking code
- Contorts code that wants to be efficient
- Makes containers, ranges and other abstractions bulkier and more difficult to define, implement, and use
- Forces exposure of raw addresses, which hurt abstraction power and safety

2. Constant-cost copy construction (via mandatory refcounting for value types):

+ Simplifies life virtually everywhere in client code
+ Makes code easy to reason about (no hidden inefficiencies, failure paths are more visible)
+ Makes generic code easier to define and more efficient for many types
- Makes value types difficult to define: a value type must store all state and do all manipulation indirectly, via a reference-counted pointer; all methods must check the pointer against null; all mutating methods must use a copy-on-write approach - Needs copy-on-write (COW) approaches in defining object types and COW is error-prone because it relies on the programmer remembering to always ensure a unique copy prior to changing the object - Can become a notable difference from C++ (and consequently a contention point for C++ programmers who are considering migrating to D): arbitrary cost of construction hurts C++ in many places, but it has contained the situation with a combination of complexity, discipline, and acceptance of inefficiencies.

Most instances of ref-counted structs in Phobos contain race conditions when put on the GC heap. ;-( That's actually a big drawback. Perhaps you should look at what fixing this implies before making this advantage/disadvantage list, as it might get a new negative point (atomic op during copy).
<http://d.puremagic.com/issues/show_bug.cgi?id=4624>

Anyway, my preferred solution to this problem is this third option:

3. Types with arbitrary-cost copying disable this(this) and define explicit dup() function.

+ Can easily implement either 2 (ref counting) or 1 (arbitrary cost copy constructor) on top of it with a standard template, so you can choose which tradeoff is best for you.
+ Can live on the stack (ref counting prohibits that).
+ If it fails, it fails either at compile time when trying to copy implicitly or early at runtime where you call dup explicitly. At this point you can either wrap it in solution 2 (ref counted template) or 1 (arbitrary copy template), or you can change your code to just bypass the problem.
- Too much flexibility might be harder to grasp.

--
Michel Fortin
[email protected]
http://michelf.com/

Reply via email to