-3

In the domain of system-modeling (e, systemVerilog, matlab, phyton), lists are obsoleting arrays, stacks and queues(*) altogether. Other domains that use python, perl and ruby have that same mindset, as well.
I am a system-modeler and a List aficionado that is new to c# and java (for hi-school teaching). c# seem so great ..but...

The Remove&Return approach is respected by :

C# Stack, C# Queue, Java ArrayList ,Python list, Perl, Ruby, e, systemverilog and others.

A notable exception is ... C# List.

c# List<T>.RemoveAt(idx) doesn't return a value.

Why is that important ? Say one wants to post this in a modeling web site (who aren't experts in c#):

 int len=myCriticalProcessList.Length; sendMethod( myCriticalProcessList.RemoveAt(len - 1)  );

That seem to work for any modern language, but to post it in c#, one has to also post several more lines, and invent new names. Also one doesn't need to know the type of the list! And when the type is changed, he does not need to change his code at all. Also naturally System modeling folks care about advanced c#, as much as c# folks care about advanced system-modeling (i.e none).

Can there be any damage if a value is returned in that case? Is there a performance consideration here? Does Java-value-return in arraylist.remove, make it slower, or less safe? Is c#'s remove&return approach good for Stack, and Queue, yet not a good idea for List? Is there some difference in underline implementation, or philosophy ?

Side note:

  • C# Stack.Pop and c# Queue.Dequeue do return a value. (a remove&return approach, like Java remove, and unlike c# RemoveAt).

  • Python's list.pop([idx]), removes-element-by-position, and returns a value. Similar to remove in java ( yet with a default, remove&return the last element).

  • C++ (stl) remove, is also void (thanks @Deduplicator). Yet, decisions relevant for languages without native-built-in-garbage-collection, are not always relevant for GC langs.

Seem @Deduplicator comment points us to the answer!!

C# was inspired by c++ not only in it's name, but also in many other things.Additionally, C# compiler was developed in C++ (in it's first ~15 years). Find me one human that is not influenced by the language he is using ... No one says it's better than Mads Torgersen, the program manager of c# : "Working in C# every day makes you think differently about C#: It’s the power of “dogfooding”." https://medium.com/microsoft-open-source-stories/how-microsoft-rewrote-its-c-compiler-in-c-and-made-it-open-source-4ebed5646f98

(*) minor: queues are not 100% obliterated by lists. There're very rare cases in system modeling were O(n) for dequeue is not tolerated.

25
  • 3
    Well, any authoritative answer is going to have to come from the design team themselves, so you're unlikely to find that here. Nevertheless, that doesn't prevent me from idly speculating. Intuitively, stacks and queues are specifically designed to add and remove things in a queue-like way, whereas List is not; it's simply a list. Note that Python's instruction is not remove, it is pop. In any case, Java's preference to return the removed item in an ArrayList is just that: a preference, easily remedied in C# by simply getting the item from the list before removing it. Commented Jan 31, 2020 at 14:00
  • 1
    While we can't definitely speak for others, it does seem reasonable to ask for probable explanations behind simple design decisions. Whether or not these explanations actually represent the thoughts of the designer seems beside the point, since the actual concern isn't so much for the designer's personal thoughts so much as to understand the widespread acceptance of a well-known design.
    – Nat
    Commented Jan 31, 2020 at 14:57
  • 4
    @Nat: Not everything has been proven to be the best choice (or to elicit a particular outcome) if no one cared about it at the time- or there was no real choice to be made at the time. It reminds me of the old joke with the child who is taught by her mother that your should always cut a sausage in two before frying it. Mom doesn't know why, but it's what her mom told her. They ask grandma, who says the same thing, her mom told her. They ask the great grandmother, who finally reveals that she used to only have a very small frying pan.
    – Flater
    Commented Jan 31, 2020 at 15:08
  • 4
    @Nat: "Why do we cut sausage in two?" is like "Why is this code like this?". The originating source (the great grandmother) can answer it. Everyone else can only say "because that's what it is", or bring forth their own speculation on why it should be done this way. But they cannot actually answer the question, which is the quality standard that StackExchange uphold for their Q&A.
    – Flater
    Commented Jan 31, 2020 at 15:10
  • 1
    Similar x-site questions stackoverflow.com/questions/5982597/…, stackoverflow.com/questions/12432248/… Commented Feb 1, 2020 at 1:50

1 Answer 1

7

Typically, people remove things from lists already knowing what those things are, as that knowledge is why they want to remove the item in the first place. By contrast, people don't usually want to remove specific known items from a stack/queue, but rather retrieve the first/last element.

Probably relevant factors:

  1. Consistency with List<T>.Remove(T).
    A List<T> has a .Remove(T) method that returns a bool indicating if the removal was successful. So, for consistency, we'd expect .RemoveAt(int) to do the same. Except .RemoveAt(int) can't really fail (unless the index is out-of-range, in which case it throws an exception instead), so it just returns void instead.

  2. Removing an item from a list doesn't imply retrieval.
    Queues/stacks are all about specific process models in which things are queued/stacked and then dequeued/popped for processing, such that removal and retrieval are conceptually linked together. By contrast, lists don't inherently imply such an operational model.

  3. Retrieval is readily available for when someone would want it.
    If a caller would want to retrieve the item at the index before removing it, then they can just specify that with list[index].

It's worth noting that a hypothetical ConcurrentList<T> would've probably implemented

partial public class ConcurrentList<T>
{
    public bool TryRemoveAt(
                int targetIndex
            ,   out T successfullyRemovedItem
        )
    { /* ... */ }
}

, analogous to a similar .TryRemove(T_Key, out T_Value) for ConcurrentDictionary<T_Key, T_Value>'s.

Finally, the main use-case of List.RemoveAt() is probably something like:

for (int i=0; i < list.count; ++i)
{
    if (someConditionalCheck(list[i]))
    {
        list.RemoveAt(i);
        break;
    }
}

, where it's important to note that break;, since if the loop continues without breaking after removal, then it'll skip an element. This could be fixed by also manually decrementing i, e.g. --i instead of break;, but at that point the code's getting pretty twisted. Plus it'd be poor form to try something like this without a break;, anyway, as list-removal is O(n), making it a poor choice of data structure to use if someone expects to loop over multiple removals as that could be O(n2).

17
  • 2
    "Typically, people remove things from lists already knowing what those things are"- in my tech domain, for 20 years, that is absolutely not the case. In Chip /System modeling/verification , removing items from a collection ( fifo or lifo) , is very common. Of course, you are unaware what the item is, before it's removed. Everyone I know (been in many teams) uses a list for such a collection, as lists offer flexibility, and are the de facto standard in System verification domain. It is not only java, but seem every language with lists, supports remove&return.
    – jsonphy
    Commented Feb 1, 2020 at 9:56
  • 2
    The classes, such as List are not part of C#; they are part of the .NET base class library. So you’d need to ask the creators of the BCL, why they wrote List the way they did. And as I pointed out in my answer to your near identical question from a couple of weeks ago, adding your own extension method to the list classes is trivial, so your question is largely irrelevant save for niche academic interest.
    – David Arno
    Commented Feb 1, 2020 at 16:30
  • 1
    @rankeren I haven't had time to read through the comments in detail, but I suspect that the folks you're referring to are using lists without thinking through what type of collection they should actually be using. In which case it's sorta like asking why a hammer isn't good at removing screws, noting that everyone at a company uses hammers to remove screws.. it's just the wrong tool, ya know?
    – Nat
    Commented Feb 1, 2020 at 18:56
  • 2
    @rankeren I mean, if you want to modify C# to have a List<> return the removed item when removing it, you can easily do that with an extension method in a few lines of code. But before doing so, you may want to ensure that the right kind of collection is being used. (Noting that lists aren't the most powerful kind of collection; they're actually fairly primitive, being a step-up from an array.)
    – Nat
    Commented Feb 1, 2020 at 18:59
  • 2
    @rankeren Unfortunately that's just poor coding. Which I don't mean to insult your coworkers, just.. it's really just like someone saying that their peers all use hammers to remove screws; what else could one make of that?
    – Nat
    Commented Feb 1, 2020 at 19:55

Not the answer you're looking for? Browse other questions tagged or ask your own question.