Reference counted containers prototype

Michel Fortin michel.fortin at michelf.com
Tue Dec 27 13:20:50 PST 2011


On 2011-12-27 15:48:56 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail at erdani.org> said:

> On 12/27/11 9:27 AM, Michel Fortin wrote:
> 
>> It can't be a library feature because it requires the compiler to
>> implicitly add a "ref" to functions parameters when they are of a "ref
>> struct" type. That's pretty much all it does: add a flag to struct
>> types, implicitly add "ref" to parameters based on that flag.
> 
> Anyhow, I think a feature would need to be tremendously justified and 
> with a huge power/weight ratio.
> This one I actually find ill-designed because now I can't look at the 
> body of a function to figure pass-by-value vs. pass-by-reference I also 
> need to look at the definition (what if it was a ref struct?). One more 
> non-modular thing to keep in mind. This is not going to fly.

I think the appeal is that it solves two common problems cleanly.

It can solve the passing of rvalue by reference so you wouldn't need to 
add yet another parameter attribute for that (if the type is a ref 
struct, this is done implicitly). And it solves the problem of passing 
containers to functions (they'd be implicitly passed by ref).

Basically, it solves the general problem where you have to decide every 
time you write a function accepting a struct whether it should be by 
value or by reference. The designer of the type chooses one behaviour 
and that behaviour is the same everywhere.

It's true that it blurs a little more the line between by-value and 
by-ref. But note that the line is already quite blurry:

You already don't know by looking at a type name whether a type is an 
alias or a class. Or even a struct that mimics reference semantics 
through internal trickery (like RefCounted). And what about dynamic 
arrays? or ranges? That whole pass-by-value vs. pass-by-reference 
dichotomy isn't as black and white as we'd like to think. You can never 
tell just by looking at the name what semantics the type has when 
"copied".

One thing it does change is it makes function parameters a special case 
where there was none before. But why do you think "const T &" is used 
all over the place for parameters but almost none elsewhere in C++? 
Simply because function parameters *are* a special case. Function 
parameters need to be passed around efficiently (hence the "&"), and 
they need to accept rvalues (hence the "const").

Everyone forget to write the "&" and the "const" once in a while in 
C++, and like you I'd like to avoid this mess in D. I'd say just make 
the best way the default: make types that should be passed by reference 
passed by reference by default. Trying to force everyone to use 
heap-allocated objects, reference counting, or other wrapping schemes 
is adding also adding much complexity, probably more than what I'm 
proposing.

For containers, the "ref struct" solution prevents fragmentation by 
packaging because whatever packaging you use for your container (GC, 
RefCounted, COW, or no packaging at all) the underlying implementation 
can always be passed by "ref" to a function. And peeling the packaging 
part also makes it easier to add const to the container (no mutable 
reference counter to update).

If you can find a better idea to solve the fragmentation problem and 
the const problem (and separately the rvalue problem), then go on. I'm 
just pointing at what seems a good idea to me. You're still free to 
find better solutions, even though I'm not convinced there are, at 
least not without forcing a one-size-fit-all packaging to everyone.

 - - -

Note that I still am in agreement with your current container prototype 
design. One important criterion to me is whether I can use the "Impl" 
part of it directly and pass it around by ref if I want. Seems like I 
can.

-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/



More information about the Digitalmars-d mailing list