May 21, 2010
Michel Fortin Wrote:

> On 2010-05-20 09:22:27 -0400, Steven Schveighoffer <schveiguy@yahoo.com> said:
> 
> > Michel Fortin Wrote:
> > 
> >> On 2010-05-20 06:34:42 -0400, Steven Schveighoffer <schveiguy@yahoo.com> said:
> >> 
> >>> I understand these points, but I'm already using interfaces to copy data between containers.  I don't have to, I could have used generic code, but this way, only one function is instantiated to copy data from all the other containers.  The problem with using generic code is that the compiler will needlessly duplicate functions that are identical.
> >> 
> >> One question. Have you calculated the speed difference between using an interface and using generic code? Surely going through all those virtual calls slows things down a lot.
> >> 
> >> I do like interfaces in principle, but I fear it'll make things much slower when people implement things in term of interfaces. That's why I'm not sure it's a good idea to offer container interfaces in the standard library.
> > 
> > It's not that much slower.  You get a much higher speedup when things can be inlined than virtual vs. non-virtual.
> 
> Yes, but that was part of the equation: a call to a template function can be inlined, not a virtual call (most of the time).

So if you want inlining, use the actual type, nothing is stopping you.  Well, except the non-final functions, I have to fix that.

> > One thing I just thought of -- in dcollections, similar types can be compared to one another.  For example, you can check to see if a HashSet is equal to a TreeSet.  But that would not be possible without interfaces.
> 
> I'm not sure of what you're saying here. Are you saying it can be done with an interface but not with a template type? Why can't this work:

Because comparing two objects for equality now calls this function:

bool opEquals(Object obj1, Object obj2)

Which is defined in object_.d in the runtime.  No compile-time anything is allowed.

-Steve
May 21, 2010
Pelle Wrote:

> On 05/20/2010 03:22 PM, Steven Schveighoffer wrote:
> > One thing I just thought of -- in dcollections, similar types can be compared to one another.  For example, you can check to see if a HashSet is equal to a TreeSet.  But that would not be possible without interfaces.
> >
> > -Steve
> 
> I'm sorry, but I think that's a misfeature. In my opinion, a tree is not equal to a hash table, ever.

They aren't trees and hashtables, they are sets.  The "quick lookup" feature is implemented via a hashtable or tree.  Basically, a set is defined by the exact elements in it, regardless of order.  Comparing two sets for equality should always be possible.

-Steve
May 21, 2010
bearophile Wrote:

> Steven Schveighoffer:
> 
> >You get a much higher speedup when things can be inlined than virtual vs. non-virtual.<
> 
> In current D compilers virtual functions prevent inlining. This can give some performance loss.

People seem to think that because dcollections implement interfaces, you must never store a concrete collection instance.  This isn't true, you can use dcollections as concrete classes without dealing with interfaces at all, and all the functions should be inlineable (at least, they will be when I change them all to final functions).

dcollections provide all of the available generic-ness that you need.  Ranges, template member functions, etc.  AND they also implement interfaces if that should be part of your design.  I've pointed out that a good use case for passing interfaces instead of concrete classes is for dynamic libraries, where you don't want to have private member changes affect runtime code.

-Steve
May 21, 2010
== Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> Andrei Alexandrescu Wrote:
> > To get back to one of my earlier points, the fact that the container interfaces are unable to express iteration is a corollary of the design's problem and an climactic disharmony.
> >
> > My vision, in very brief, is to foster a federation of independent containers abiding to identical names for similar functionality. Then a few concept checks (a la std.range checks) can easily express what capabilities a given client function needs from a container.
> This might have a simple answer.  Dcollections implementations are not a
hierarchy, just the interfaces are.  I.e. there aren't many kinds of HashMaps that derive from each other.  But the interfaces are not detrimental to your ideas. The only thing interfaces require is that the entities implementing them are classes and not structs.  As long as you agree that classes are the right call, then interfaces can co-exist with your other suggestions without interference.

classes suck ass. structs give ye freedom 2 define copy ctors n shit. haven't seen andre agreein' classes are da way 2 go and i hope he don't. anyway u put together some cool shit. hope andre & u do a pow-wow n shit and adjust shit fer puttin' into phobos.
May 21, 2010
superdan Wrote:

> == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> > Andrei Alexandrescu Wrote:
> > > To get back to one of my earlier points, the fact that the container interfaces are unable to express iteration is a corollary of the design's problem and an climactic disharmony.
> > >
> > > My vision, in very brief, is to foster a federation of independent containers abiding to identical names for similar functionality. Then a few concept checks (a la std.range checks) can easily express what capabilities a given client function needs from a container.
> > This might have a simple answer.  Dcollections implementations are not a
> hierarchy, just the interfaces are.  I.e. there aren't many kinds of HashMaps that derive from each other.  But the interfaces are not detrimental to your ideas. The only thing interfaces require is that the entities implementing them are classes and not structs.  As long as you agree that classes are the right call, then interfaces can co-exist with your other suggestions without interference.
> 
> classes suck ass. structs give ye freedom 2 define copy ctors n shit. haven't seen andre agreein' classes are da way 2 go and i hope he don't. anyway u put together some cool shit. hope andre & u do a pow-wow n shit and adjust shit fer puttin' into phobos.

I think classes are the right move.  First, a collection makes more sense as a reference type.  Note that both arrays and associative arrays are reference types.  If collections are value types, like in C++, then copying a collection that is a node-based collection means duplicating all the nodes.  Copy construction is essentially possible through a function -- dup.  Having value-semantics makes it too easy to copy large amounts of heap data hurting performance.  Many inexperienced C++ coders pass a std::set by value, not realizing why their code is so ridiculously slow.  I think one of the things that makes D so damn fast is because large data structures such as arrays and AA's are always passed by reference.

Second, since reference types are the right thing to do, classes are much easier to deal with.  I know AA's are reference types that are structs, but the code needed to perform this feat is not trivial.  The AA has only one member, a reference to the data struct, which is allocated on the heap.  Any member function/property that is used on the AA must first check whether the implementation is allocated yet.  The only benefit this gives you IMO is not having to use 'new' on it.  And even that has some drawbacks.  For example, pass an empty AA by value to a function, and if that function adds any data to it, it is lost.  But pass an AA by value with one element in it, and the new data sticks.  A class gives you much more in terms of options -- interfaces, builtin synchronization, runtime comparison, etc.  And it forces full reference semantics by default.  I think regardless of whether interfaces are defined for dcollections, classes give a better set of options than structs.

Also note that I intend to make all dcollections classes final, so there will be no virtual calls as long as you have a reference to the concrete type.

Is there some other reason to use structs besides copy construction?

-Steve
May 21, 2010
== Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> superdan Wrote:
> > == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> > > Andrei Alexandrescu Wrote:
> > > > To get back to one of my earlier points, the fact that the container interfaces are unable to express iteration is a corollary of the design's problem and an climactic disharmony.
> > > >
> > > > My vision, in very brief, is to foster a federation of independent containers abiding to identical names for similar functionality. Then a few concept checks (a la std.range checks) can easily express what capabilities a given client function needs from a container.
> > > This might have a simple answer.  Dcollections implementations are not a
> > hierarchy, just the interfaces are.  I.e. there aren't many kinds of HashMaps that derive from each other.  But the interfaces are not detrimental to your ideas. The only thing interfaces require is that the entities implementing them are classes and not structs.  As long as you agree that classes are the right call, then interfaces can co-exist with your other suggestions without interference.
> >
> > classes suck ass. structs give ye freedom 2 define copy ctors n shit. haven't seen andre agreein' classes are da way 2 go and i hope he don't. anyway u put together some cool shit. hope andre & u do a pow-wow n shit and adjust shit fer puttin' into phobos.
> I think classes are the right move.  First, a collection makes more sense as a
reference type.  Note that both arrays and associative arrays are reference types.
 If collections are value types, like in C++, then copying a collection that is a
node-based collection means duplicating all the nodes.  Copy construction is
essentially possible through a function -- dup.  Having value-semantics makes it
too easy to copy large amounts of heap data hurting performance.  Many
inexperienced C++ coders pass a std::set by value, not realizing why their code is
so ridiculously slow.  I think one of the things that makes D so damn fast is
because large data structures such as arrays and AA's are always passed by reference.
> Second, since reference types are the right thing to do, classes are much easier
to deal with.  I know AA's are reference types that are structs, but the code
needed to perform this feat is not trivial.  The AA has only one member, a
reference to the data struct, which is allocated on the heap.  Any member
function/property that is used on the AA must first check whether the
implementation is allocated yet.  The only benefit this gives you IMO is not
having to use 'new' on it.  And even that has some drawbacks.  For example, pass
an empty AA by value to a function, and if that function adds any data to it, it
is lost.  But pass an AA by value with one element in it, and the new data sticks.
 A class gives you much more in terms of options -- interfaces, builtin
synchronization, runtime comparison, etc.  And it forces full reference semantics
by default.  I think regardless of whether interfaces are defined for
dcollections, classes give a better set of options than structs.
> Also note that I intend to make all dcollections classes final, so there will be
no virtual calls as long as you have a reference to the concrete type.
> Is there some other reason to use structs besides copy construction? -Steve

memory management n shit. with a struct u can use refcounting n malloc n realloc n shit. still stays a reference type. nothing gets fucked up.

den there's all that null ref shit. with a class u have

void foo(container!shit poo)
{
    poo.addElement(Shit(diarrhea));
}

dat works with struct but don't work with motherfucking classes. u need to write.

void foo(container!shit poo)
{
    if (!poo) poo = new container!shit; // fuck dat shit
    poo.addElement(Shit(diarrhea));
}

u feel me?
May 21, 2010
superdan Wrote:

> == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article

> > Is there some other reason to use structs besides copy construction? -Steve
> 
> memory management n shit. with a struct u can use refcounting n malloc n realloc n shit. still stays a reference type. nothing gets fucked up.

This is not necessary with purely memory-based constructs -- the GC is your friend.  The custom allocator ability in dcollections should provide plenty of freedom for memory allocation schemes.

> 
> den there's all that null ref shit. with a class u have
> 
> void foo(container!shit poo)
> {
>     poo.addElement(Shit(diarrhea));
> }
> 
> dat works with struct but don't work with motherfucking classes. u need to write.
> 
> void foo(container!shit poo)
> {
>     if (!poo) poo = new container!shit; // fuck dat shit
>     poo.addElement(Shit(diarrhea));
> }
> 
> u feel me?

It doesn't work.  Just with your example, you won't get what you expect.  Try it with AA's.

Even your class example doesn't make any sense.

-Steve
May 21, 2010
== Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> superdan Wrote:
> > == Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> > > Is there some other reason to use structs besides copy construction? -Steve
> >
> > memory management n shit. with a struct u can use refcounting n malloc n realloc n shit. still stays a reference type. nothing gets fucked up.
> This is not necessary with purely memory-based constructs -- the GC is your
friend.  The custom allocator ability in dcollections should provide plenty of freedom for memory allocation schemes.

how do u set up yer custom allocator to free memory? u cant tell when its ok. copying refs iz under da radar. dats my point.

> > den there's all that null ref shit. with a class u have
> >
> > void foo(container!shit poo)
> > {
> >     poo.addElement(Shit(diarrhea));
> > }
> >
> > dat works with struct but don't work with motherfucking classes. u need to write.
> >
> > void foo(container!shit poo)
> > {
> >     if (!poo) poo = new container!shit; // fuck dat shit
> >     poo.addElement(Shit(diarrhea));
> > }
> >
> > u feel me?
> It doesn't work.

wut? it don't work? whaddaya mean it dun work? is you crazy? what dun work? maybe therez sum misundercommunication. repeating. if container is struct this shit works:

void foo(container!shit poo)
{
    poo.addElement(Shit(diarrhea));
}

dun tell me it dun work. i dun explain shit again. it works coz a struct cant be null. but a struct can be a ref if it only haz one pointer inside. methinks the builtin hash iz dat way.

if container iz class dat shit dun work. u need to write dis shit:

void foo(container!shit poo)
{
    if(!poo) poo = new container!shit; // fuck dat shit
    poo.addElement(Shit(diarrhea));
}

dat sucks bull ballz.
May 21, 2010
On 05/21/2010 09:14 AM, Steven Schveighoffer wrote:
> Second, since reference types are the right thing to do, classes are much easier to deal with.  I know AA's are reference types that are structs, but the code needed to perform this feat is not trivial.  The AA has only one member, a reference to the data struct, which is allocated on the heap.  Any member function/property that is used on the AA must first check whether the implementation is allocated yet.  The only benefit this gives you IMO is not having to use 'new' on it.  And even that has some drawbacks.  For example, pass an empty AA by value to a function, and if that function adds any data to it, it is lost.  But pass an AA by value with one element in it, and the new data sticks.  A class gives you much more in terms of options -- interfaces, builtin synchronization, runtime comparison, etc.  And it forces full reference semantics by default.  I think regardless of whether interfaces are defined for dcollections, classes give a better set of options than structs.


Wow. A partially-nullable type.

Great. Now I have to review everywhere I ever used an AA. Thanks, D.

is there any serious drawback to something like

(int[int]).init = InitializedAA!(int,int)

?
May 21, 2010
On 05/19/2010 07:21 PM, bearophile wrote:
> Andrei Alexandrescu:
>> Destroy me :o).
>
> You ideas are surely interesting, but I don't think there's a simple
> way to change his code according to your ideas. People can use the
> dcollections in the following weeks and months, and when you have
> implemented your ideas the people that like them can switch to using
> your collections.
>
> Bye, bearophile

I actually believe there is a simple transition path. In essence the interfaces in model/ should be rewritten as isXxx tests and the containers should have all of their methods final.

Andrei