May 20, 2010
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.

I don't think the ideas are mutually exclusive.  I don't see why having an interface prevents someone from using a concept on the concrete class.

> 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.

If it's at all possible, I'd like to cooperate on making dcollections phobos-qualified.  So I'm glad to try and find a way to satisfy Andrei's concerns.

-Steve
May 20, 2010
Steven Schveighoffer:
> If it's at all possible, I'd like to cooperate on making dcollections phobos-qualified.  So I'm glad to try and find a way to satisfy Andrei's concerns.

Very good. Sometimes I am a too much pessimistic person :-)

Bye,
bearophile
May 20, 2010
On 2010-05-19 19:01:51 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> I wrote a solution to the problem in native D. It goes like this:
> 
> alias Container!(int, addable | purgeable) Messerschmidt;
> 
> void messWith(Messerschmidt i) {
>      ... use i's capabilities to add and purge ...
> }

Are you sure this is necessary? I'm wondering how the above is different from:

void messWith(C)(C i) if (IsAddable!C && IsPurgeable!C) {
	... use i's capabilities to add and purge
}

where IsAddable just checks for an 'add' function and IsPurgeable checks for a 'purge' function. Obviously, one is a template and the other isn't. I'd expect the template function to be more performant since it doesn't require an indirection to call into the container. Is the need for runtime-swappable containers really common enough to justify adding it to the standard library? Won't adding this encourage people to use it without realizing the downside in performance and failed optimization opportunities because of the hidden dynamic dispatch? It's a quite nice idea, but I don't like the tradeoff.

This criticism is valid for containers implementing interfaces too. In my first Java programs, I was always declaring variables as the List interface, then instantiating an ArrayList for them, thinking it'd make things more generic and easier to change later. Generic sometime is good, but if you do that with containers in D you're in for an important performance drop. Personally, I'd scrap anything that's not made of static calls (final functions in a class are fine) so people can't easily make these kind of mistakes (and then believe D is slow).

Also, addable and purgeable above being or'ed constants makes the system difficult to scale to new concepts. The template predicates on the other hand are infinitely extendable: if my containers have 'commit' and 'rollback' functions, I can define IsTransactional to check for the presence of the functions and make some algorithms that benefits from this. In fact, this can apply to anything, not just containers. Range are already using this pattern. Wouldn't it make things easier to learn if we could just reuse the same principle with containers?


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

May 20, 2010
On Wed, 19 May 2010 21:42:35 -0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> 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.
>
> Yes, if you want to define "this function needs something that is both addable and purgeable, I don't have an interface for that.  But a concept can certainly define that generically (which is what you want anyways), or you could just say "I need a List" and get those functions also.  It also does not force entities other than dcollections objects to be classes, they could be structs and implement the correct concepts.
>
> I myself don't really use the interface aspect of the classes, it is mostly a carryover from the Java/Tango inspirations.  But I can see one good reason to keep them -- binary interoperability.  For example, it might be the case some day when D has good support with dynamic libraries that a library exposes some piece of itself as a Map or List interface.
>
> So my answer is -- go ahead and define these concepts and required names, and you can ignore the interfaces if they don't interest you.  They do not subtract from the possibilities, and others may find good use for them.
>
> Does that make sense?
>
> -Steve

Yes and No. I understand where your coming from, but I think it's a bad idea. First, I think it needlessly expands the radius of comprehension needed to understand and use the library. (See Tangled up in tools http://www.pragprog.com/magazines/2010-04/tangled-up-in-tools) Second, I think designing a library to be flexible enough to meet some future, anticipated need (e.g. dlls) is a good idea, but actually implementing vaporous future needs is fraught with peril; it's too easy to guess wrong. Third, interface base design is viral; If library X uses interfaces then I have to use interfaces to interface with it. And if another library Y uses classes, then I'm going have to write a (needless) wrapper around one of them.
May 20, 2010
On 20/05/10 13:39, Bernard Helyer wrote:
> Oooohhh goody goody goody!  n_n
>
>
> I'm in the process of making a little toy project ATM. I'll shall
> integrate dcollections 2.0a into ASAP.

ArrayList doesn't compile with warnings as it overrides opEquals, but doesn't mark it as such.
May 20, 2010
On 20/05/10 18:11, Bernard Helyer wrote:
> On 20/05/10 13:39, Bernard Helyer wrote:
>> Oooohhh goody goody goody! n_n
>>
>>
>> I'm in the process of making a little toy project ATM. I'll shall
>> integrate dcollections 2.0a into ASAP.
>
> ArrayList doesn't compile with warnings as it overrides opEquals, but
> doesn't mark it as such.

And lines 772 and 780 complained about not being able to implicitly cast const(Thing) to Thing. Which is strange, because T was Thing. Inserting cast(Thing) seemed to 'fix' it. D=
May 20, 2010
On 20/05/10 18:16, Bernard Helyer wrote:
> On 20/05/10 18:11, Bernard Helyer wrote:
>> On 20/05/10 13:39, Bernard Helyer wrote:
>>> Oooohhh goody goody goody! n_n
>>>
>>>
>>> I'm in the process of making a little toy project ATM. I'll shall
>>> integrate dcollections 2.0a into ASAP.
>>
>> ArrayList doesn't compile with warnings as it overrides opEquals, but
>> doesn't mark it as such.
>
> And lines 772 and 780 complained about not being able to implicitly cast
> const(Thing) to Thing. Which is strange, because T was Thing. Inserting
> cast(Thing) seemed to 'fix' it. D=

Sorry about the blow by blow, but the cursor thing seems to work well in my situation. Me likey dcollections very much so far. Go Steve!
May 20, 2010
Robert Jacques Wrote:

> On Wed, 19 May 2010 21:42:35 -0400, Steven Schveighoffer
> >
> > Does that make sense?
> >
> > -Steve
> 
> Yes and No. I understand where your coming from, but I think it's a bad idea. First, I think it needlessly expands the radius of comprehension needed to understand and use the library. (See Tangled up in tools http://www.pragprog.com/magazines/2010-04/tangled-up-in-tools) Second, I think designing a library to be flexible enough to meet some future, anticipated need (e.g. dlls) is a good idea, but actually implementing vaporous future needs is fraught with peril; it's too easy to guess wrong. Third, interface base design is viral; If library X uses interfaces then I have to use interfaces to interface with it. And if another library Y uses classes, then I'm going have to write a (needless) wrapper around one of them.

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.

Using interfaces is not as viral as you think.  My interfaces can be used in generic code, as long as the generic code uses functions in the interfaces.  If a library returns an interface, the author is saying "I don't want you using any functions outside this interface," so why is that a bad thing?

Forcing people to *not* use interfaces has its drawbacks too.  Dcollections gives the most flexible design I could muster, while still being useful.

I'm not saying I'm against removing the interfaces until some later date, but I don't see any convincing arguments yet, especially since I've already seen benefits from having them.

-Steve
May 20, 2010
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.

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

May 20, 2010
Michel Fortin:

> Surely going through all those virtual calls slows things down a lot.<

Right. But the purpose of a good compiler is to kill those, devirtualizing. LLVM devs are working on this too. See:
http://llvm.org/bugs/show_bug.cgi?id=6054
http://llvm.org/bugs/show_bug.cgi?id=3100

---------------------

Steven Schveighoffer:

>The problem with using generic code is that the compiler will needlessly duplicate functions that are identical.<

See the  -mergefunc  compiler switch of LDC, to merge identical functions (like ones produced by template instantiations). This feature is not very powerful yet, but it's present and I have seen it works. See:
http://llvm.org/bugs/show_bug.cgi?id=6712
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=108275

Bye,
bearophile