Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Typical context: I make an extension method for a collection which considers that the elements are ordered. The function starts at the beginning, at index 0, and the order has significance. Examples: Grouping by sequence or Indexes of an item.

However, I'm always stumped as to what to extend: IEnumerable<T> or T[]. My rationale was clarity of purpose: An array has a notion of ordering, whereas an IEnumerable is implemented by many generic collections, not all of which have a notion of order:

  • Dictionary - unordered
  • HashSet - unordered
  • LinkedList - ordered
  • List - ordered
  • Queue - ordered
  • SortedDictionary - sorted (not original order)
  • SortedList - sorted (not original order)
  • SortedSet - sorted (not original order)
  • Stack - reversed

As well as any other implementation which might or might not be ordered.

Also, I'm not certain if the enumerator is reset if an enumeration is not completed, so if that's a worry, then who knows at what point the enumeration would start? Enumerating an array would always start at the beginning.

So to me, it makes more sense to extend a T[]. But am I correct in thinking that? Am I worrying too much? What's the proper approach for ensuring "ordered" enumeration?

share|improve this question
add comment

3 Answers 3

up vote 8 down vote accepted

I'm not certain if the enumerator is reset if an enumeration is not completed, so if that's a worry, then who knows at what point the enumeration would start? Enumerating an array would always start at the beginning.

These two sentences make me think that you have deep misunderstandings about how the enumerable pattern works. Can you explain why you think that an abandoned enumerator has anything whatsoever to do with a later enumeration?

An enumerable is a device which produces enumerators. If an enumerator is abandoned, that does not in any way affect the enumerable. If I sell books, and Bob buys a book and only reads it halfway, that doesn't mean that when I sell a different copy of the book to Alice, she has to start reading where Bob left off.

I'm always stumped as to what to extend: IEnumerable<T> or T[]. My rationale was clarity of purpose: An array has a notion of ordering, whereas an IEnumerable is implemented by many generic collections, not all of which have a notion of order:

Does your extension method need to (1) access the collection out of order? (2) write to the collection?

If so, then extend IList<T> If not, extend IEnumerable<T>.

What about: (3) pass the collection on to a method that expects an array?

Then extend array.

Your question is basically "I don't know whether to extend Animal or Giraffe". If your extension method is not specific to Giraffes, extend Animal. If your extension method is not specific to arrays, extend all lists. If it is not specific to lists, extend all sequences. If it is not specific to sequences, odds are good that an extension method is the wrong mechanism for you; I recommend against extending all objects.

share|improve this answer
    
I do have a great, shameful lack of knowledge of how the enumerable pattern works. I guess that's why I'm here asking this. –  MPelletier Dec 9 '11 at 11:00
    
Damn, I'd totally forgotten my data structure class. Of course it doesn't affect later enumerations! I've covered myself in shame... :( –  MPelletier Dec 9 '11 at 11:05
    
@MPelletier: Your question still holds value. Is it safe/does it make sense to run an algorithm where order is of importance on e.g. a Dictionary? Probably not. As Scott Meyers said: "The best way to prevent incorrect use is to make such use impossible.". Is it possible/would it be beneficial to do so in this scenario? –  Steven Jeuris Dec 9 '11 at 11:50
1  
@EricLippert: The 3 points you mentioned are reasons why you have to extend array. The real question is, as in my previous comment, would it be worthwhile preventing incorrect usage? Hoping you can expand a bit on that ... –  Steven Jeuris Dec 9 '11 at 11:55
add comment

I think that you want to combine 2 different concepts into 1. The data structure and its contents order are 2 separate things.

Ordering is a tricky subject. For example, what does ordering a list of persons mean? Even when order/sort key is defined, it has to have a direction and you have to decide what to do with nulls (if any), date issues, etc.

If data ordering is important to your method, then may be your method should be responsible for the ordering of the data as part of its set up instead of asking data to be ordered by the caller. A similar approach is used by some string match algorithms where a dictionary is built inside the search method from the passed string before the string is searched. I know this is not the exact case, but it is the closest example I could think of.

share|improve this answer
2  
An ordering method as an argument... Hmmm, interesting! –  MPelletier Dec 9 '11 at 2:55
    
Even then, the order could be implicit. That's the main issue I'm having. I understand that the concept of LINQ is to emulate database functions, and as per 1NF, records are unordered. Unfortunately, the real world is rarely 1NF. –  MPelletier Dec 9 '11 at 3:37
    
"the real world is rarely 1NF", is true in some cases, but I am not sure how would that affect the case you describe here? –  Emmad Kareem Dec 9 '11 at 4:15
    
1NF: "There's no top-to-bottom ordering to the rows." That's what's happening here, I think. There IS top-to-bottom ordering in logs, in lots of loose "collections". LINQ is designed to work on collections as if they were databases, but there can be top-to-bottom ordering, hence the contradiction I just saw. –  MPelletier Dec 9 '11 at 10:55
add comment

IEnumerable declares that the collection you have can be enumerated; it doesn't imply anything about the content. This isn't a bad thing -- containers can have additional capabilities and restrictions on top of individual interfaces.

(I don't see how an array is any better here -- it's indexable, as is an IList and other containers, but there is nothing about indexing that implies data order. Your list is kind of odd -- some items are "ordered" in that they preserve insertion order, others are "ordered" as in they are sorted. They are two different things. Other than the SortedSet/SortedList/SortedDictionary, you shouldn't assume the data is in a particular order unless you handle that inside your own code.)

However, IEnumerable provides a LINQ extension that allows you to .OrderBy, so anything that is enumerable can be returned in an IOrderedEnumerable sorted order. That's a LINQ-specific interface though (and not implemented by default by SortedSet/SortedList/SortedDictionary, so it might not make sense to extend that particular interface...)

share|improve this answer
2  
What I want to avoid is making a series of functions which work "only if ordered", then months later someone uses the library on an unordered collection and wonders why it's giving funky results. Besides good documentation which everyone will have read thoroughly, of course. –  MPelletier Dec 9 '11 at 1:56
    
And I fixed the list. Thanks for pointing it out. –  MPelletier Dec 9 '11 at 1:57
    
And I don't think extending IOrderedEnumerable will make me any fans. Some lists are already ordered (think a parsed log file, for example. The order is the line number, but there's no point to sort by it if it was read sequentially. –  MPelletier Dec 9 '11 at 2:07
    
There is not an decorator/interface today that can tell you/warn users that a sorted collection is needed for your extension method. Especially for arbitrary data, how would you know (without a comparer function) whether the data was ordered or not? –  Joe Dec 9 '11 at 3:08
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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