improvement request - enabling by-value-containers

Simon Buerger krox at gmx.net
Thu Dec 9 13:55:16 PST 2010


On 08.12.2010 23:45, Jonathan M Davis wrote:
> On Wednesday, December 08, 2010 14:14:57 Simon Buerger wrote:
>> For Every lib its a design descision if containers should be value- or
>> reference-types. In C++ STL they are value-types (i.e. the
>> copy-constructor does a real copy), while in tango and phobos the
>> descision was to go for reference-types afaik, but I would like to be
>> able to write value-types too, which isn't possible (in a really good
>> way) currently. Following points would need some love (by-value
>> containers are probably not the only area, where these could be useful)
>
> It's extremely rare in my experience that it makes any sense to copy a container
> on a regular basis. Having an easy means of creating a deep copy of a container
> or copying the elements from one container to another efficiently would be good,
> but having containers be value types is almost always a bad idea. It's just not
> a typical need to need to copy containers - certainly not enough to have them be
> copied just because you passed them to a function or returned them from one. I
> think that reference types for containers is very much the correct decision.
> There should be good ways to copy containers, but copying shouldn't be the
> default for much of anything in the way of containers.

 From a pragmatic viewpoint you are right, copying containers is rare. 
But on the other hand, classes imply a kind of identity, so that a set 
is a different obejct then an other object with the very same 
elements. That feels wrong from an aesthetical or mathematical 
viewpoint. Furthermore, if you have for example a vector of vectors,

vector!int row = [1,2,3];
auto vec = Vector!(Vector!int)(5, row);

then vec should be 5 rows, and not 5 times the same row.

>> (1) Allow default-constructors for structs
>> I don't see a reason, why "this(int foo)" is allowed, but "this()" is
>> not. There might be some useful non-trivial init to do for complex
>> structs.
>
> It has to do with the init property. It has to be known at compile-time for all
> types. For classes, that's easy because it's null, but for structs, that's what
> all of their member variables are directly initialized to. If you add a default
> constructor, then it would have to be to whatever that constructed them to,
> which would shift it from compile time to runtime. It should be possible to have
> default constructors which are definitely limited in a number of ways (like
> having to be nothrow and possibly pure), but that hasn't been sorted out, and
> even if it is, plenty of cases where people want default constructors still
> wouldn't likely work. It just doesn't work to have default constructors which
> can run completely arbitrary code. You could get exceptions thrown in weird
> places and a variety of other problems which we can't have in situations where
> init is used. Hopefully, we'll get limited default constructors at some point,
> but it hasn't happened yet (and probably won't without a good proposal that
> deals with all of the potentiall issues), and regardless, it will never be as
> flexible as what C++ does. It's primarily a side effect of insisting that all
> variables be default initialized if they're not directly initialized.

I partially see your point, the constructor would be called in places 
the programmer didnt expect, but actually, what's the problem with an 
exception? They can always happen anyway (at least outOfMemory)

>> (2) const parameters by reference
>> If a parameter to a function is read-only, the right notion depends on
>> the type of that parameter. I.e. "in" for simple stuff like ints, and
>> "ref const" for big structures. Using "in" for big data implies a
>> whole copy, even though it's constant, and using "ref const" for
>> simple types is a useless indirection. This is a problem for generic
>> code, when the type is templated, because there is now way to switch
>> between "in" and "ref const" with compile-time-reflection.
>>
>> Solution one: make "ref" a real type-constructor, so you could do the
>> following (this is possible in C++):
>>
>> static if(is(T == struct))
>> 	alias ref const T const_type;
>> else
>> 	alias const scope T const_type;
>> // "const scope" is (currently) equivalent to "in"
>> void foo(const_type x)
>>
>> Solution two: let "in" decide wheather to pass by reference or value,
>> depending on the type. Probably the better solution cause the
>> programmer dont need to care of the descision himself anymore.
>
> I think that auto ref is supposed to deal with some of this, but it's buggy at
> the moment, and I'm not sure exactly what it's supposed to do. There was some
> discussion on this one in a recent thread.

letting "in" decide would be cleaner IMO, but anyway good to hear that 
problem is recognized. Will look for the other thread.

>> (3) make foreach parameters constant
>> when you do "foreach(x;a)" the x value gets copied in each iteration,
>> once again, that matters for big types especially when you have a
>> copy-constructor. Current work-around is prepending "ref": nothing
>> gets copied, but the compiler wont know it is meant to be read-only.
>> Solution: either allow "ref const" or "in" in foreach. Or you could
>> even make x default to constant if not stated as "ref" explicitly.
>> Last alternative seems logical to me, but it may break existing code.
>
> I'd hate to see foreach variables be const by default. That would be overly
> limiting and would definitely break a lot of code. Making ref const work properly
> would be good (I think that it works in at least some cases) for structs that
> you don't want to be copied but wouldn't be all that useful otherwise. Nothing
> in D is const by default, and I think that making anything const by default
> would clash with the rest of the language. Particularly since then how would you
> make it mutable? No, it should be possible to have const refs to structs for
> foreach variables, but it shouldn't be the default. The language as a whole just
> does not support that.

You are right that default-const would be contrary to the rest of the 
language, but when I think longer about this... the same default-const 
should apply for all function parameter. They should be input, output 
or inout. But the "mutable copy of the original" which is common in 
C/C++/D/everything-alike, is actually pretty weird. (modifying 
non-output parameters inside a function is considered bad style even 
in C++ and Java). But well, that would be really a step too big for 
D2... maybe I'll suggest it for D3 some day *g*

Krox


More information about the Digitalmars-d mailing list