On Wed, 02 Nov 2011 19:24:03 -0400, Max Wolter <awishform...@gmail.com> wrote:

On 11/2/2011 2:41 PM, Steven Schveighoffer wrote:

I never said you couldn't (and I've even given examples of such
implementations). It's just not neatly packaged into a method.

But again, if the method is exactly the same as the efficient version
for other containers, it becomes *impossible* to design an algorithm
that guarantees any sort of complexity. As I said before, quadratic sort
is epic fail, and needs to always be avoided.

I'll give you a scenario:

People often complain that Linked List does not have an opIndex on it.
Yes it's inefficient, but so what? "I know it's inefficient, let me
decide whether it's worth it or not."

So let's say I add it to LinkList. Those people are happy.

But now, LinkList becomes defined as a *random-access-range* according
to std.ranges. Therefore, std.algorithm.sort(linklist) compiles! And is
now something like O(n^3).

Whereas LinkList already defines a sort method, which uses mergesort
(O(nlgn)). So are you going to realize this when reading someones code
and you see:

sort(somelist);

That it's going to be horribly inefficient? Why shouldn't we strive for
a library where such things just don't compile?


Hello.

You generally arguing this is all nice and good, but this is a very specific case.

I am using a LinkList because in my code, the elements are iterated over a million times and during this, I add stuff in-between elements all the time. However, I will be removing stuff *very* rarely. I am thus using the appropriate container and it doesn't matter whether the remove will be inefficient.

A linked list (any list really) is important if you want to maintain insertion order. If that's not important, don't use a list, a hash or tree is about as efficient. There exist (not in D) hybrid container types that allow O(1) removal using value, and maintain insertion order.

In fact, the actual remove is not inefficient if you have a reference to an element (not just the value). Unfortunately, for SList, this is not the case, but it should be fixed at some point.

But I still maintain, anything in std.container is not just a container for your code, it's a container that tries to cater to the most common needs. If you want a remove(value) function, it is trivial to write.

To put it another way: if removing elements was of crucial importance to the performance of my code in the first place, I wouldn't (and shouldn't) be using a LinkList.

As long as you don't need to search for the element to remove using its value, removal in a linked list should be O(1). A linked list that does not allow O(1) removal and O(1) insertion given a topological reference is a failure (yes, that includes the current version of SList).

Therefore, implementing an inefficient method which does this won't be of consequence. Finally, the fundamental statement I'm trying to make here is: adding and removing *single* elements should be a straightforward method call for *any* container.

Adding, yes. Removing a container-selected element, yes. Removing a *specific* element, no. Inserting an element in a *specific location*, no. std.container has taken the stance that primitives should reflect the efficiency of the operation.

This is not the only valid position to have. It's just std.container's position. For example, Java allows this.

As a side note, your example about generic programming is really neat and makes sense; personally, I would never want a linked list with indexes and it's also a horrible analogy to the complaint at hand.

People have asked for it and argued vigorously for it on this newsgroup, just as you are arguing for this.

-Steve

Reply via email to