DaedTech

Stories about Software

By

What To Return: IEnumerable or IList?

I’ve received a couple of requests in various media to talk about this subject, with the general theme being “I want to return a bunch of things, so what type of bunch should I use?” I’m using the term “bunch” in sort of a folksy, tongue-in-cheek way, but also for a reason relating to precision — I can’t call it a list, collection or group without evoking specific connotations of what I’d be returning in the C# world (as those things are all type names or closely describe typenames).

So, I’m using “bunch” to indicate that you want to return a “possibly-more-than-one.”

I suspect that the impetus for this question arises from something like a curt code review or offhand comment from some developer along the lines of “you should never return a list when you could return an IEnumerable.” The advice lacks nuance for whatever reason and, really, life is full of nuance.

So when and where should you use what? Well, the stock consultant answer of “it depends” makes a good bit of sense. You’ll also probably get all kinds of different advice from different people, but I’ll describe how I decide and explain my reasoning.

First Of All, What Are These Things?

Before we go any further, it probably makes sense to describe quickly what each of these possible return values is.

IList is probably simpler to describe. It’s a collection (I can use this because it inherits from ICollection) of objects that can be accessed via indexers, iterated over and (usually) rearranged. Some implementations of IList are readonly, others are fixed size, and others are variable size. The most common implementation, List, is basically a dynamic array for the sake of quick, easy understanding.

I’ve blogged about IEnumerable in the past and talked about how this is really a unique concept. Tl;dr version is that IEnumerable is not actually a collection at all (and it does not inherit from ICollection), but rather a combination of an algorithm and a promise.

If I return an IEnumerable to you, what I’m really saying is “here’s something that when you ask it for the next element, it will figure out how to get it and then give you the element until you stop asking or there are none left.” In a lot of cases, something with return type IEnumerable will just be a list under the hood, in which case the “strategy” is just to give you the next thing in the list.

But in some cases, the IEnumerable will be some kind of lazy loading scheme where each iteration calls a web service, hits a database, or for some reason invokes a 45 second Thread.Sleep. IList is (probably) a data structure; IEnumerable is a algorithm.

Since they’re different, there are cases when one or the other clearly makes sense.

When You’d Clearly Use IEnumerable

Given what I’ve said, IEnumerable (or perhaps IQueryable) is going to be your choice when you want deferred execution (you could theoretically implement IList in a way that provided deferred execution, but in my experience, this would violate the “principle of least surprise” for people working with your code and would be ill-suited since you have to implement the “Count” property).

If you’re using Entity Framework or some other database loading scheme, and you want to leave it up the code calling yours when the query gets executed, return IEnumerable. In this fashion, when a client calls the method you’re writing, you can return IEnumerable, build them a query (say with Linq), and say “here, you can have this immediately with incredible performance, and it’s up to you when you actually want to execute this thing and start hammering away at the database with retrieval tasks that may take milliseconds or seconds.”

Another time that you would clearly want IEnumerable is when you want to tell clients of your method, “hey, this is not a data structure you can modify — you can only peek at what’s there. If you want your own thing to modify, make your own by slapping what we give you in a list.”

To be less colloquial, you can return IEnumerable when you want to make it clear to consumers of your method that they cannot modify the original source of information. It’s important to understand that if you’re going to advertise this, you should probably exercise care in how the thing you’re returning will behave. What I mean is, don’t return IEnumerable and then give your clients something where they can modify the internal aggregation of the data (meaning, if you return IEnumerable don’t let them reorder their copy of it and have that action also reorder it in the place you’re storing it).

When you’d clearly use IList

By contrast, there are times when IList makes sense, and those are probably easier to understand.

If, for instance, your clients want a concrete, tangible, and (generally) modifiable list of items, IList makes sense.

  • If you want to return something with an ordering that matters and give them the ability to change that ordering, then give them a list.
  • If they want to be able to walk the items from front to back and back to front, give them a list.
  • Or, if they want to be able to look up items by their position, give them a list.
  • And if they want to be able to add or remove items, give them a list. Any random accesses and you want to provide a list.

Clearly, it’s a data structure you can wrap your head around easily — certainly more so than IEnumerable.

Good Polymorphic Practice

With the low hanging fruit out of the way, let’s dive into grayer areas. A rule of thumb that has served me well in OOP is “accept as generic as possible, return as specific as possible.” This is being as cooperative with client code as possible.

Imagine if I write a method called “ScareBurglar()” that takes an Animal as argument and invokes the Animal’s “MakeNoise()” method. Now, imagine that instead of taking Animal as the parameter, ScareBurglar took Dog and invoked Dog.MakeNoise(). That works, I suppose, but what if I had a guard-bear? I think the bear could make some pretty scary noises, but I’ve pigeon-holed my clients by being too specific in what I accept.

If MakeNoise() is a method on the base class, accept the base class so you can serve as many clients as possible.

On the flip side, it’s good to return very specific types for similar kinds of reasoning. If I have a “GetDog()” method that instantiates and returns a Dog, why pretend that it’s a general Animal? I mean, it’s always going to be a Dog anyway, so why force my clients that are interested in Dog to take an Animal and cast it?

I’ve blogged previously about what I think of casting. Be specific. If your clients want it to be an animal, they can just declare the variable to which they’re assigning the return value as Animal.

So, with this rule of thumb in mind, it would suggest that returning lists is a good idea when you’re definitely going to return a list. If your implementation instantiates a list and returns that list, with no possibility of it being anything else, then you might want to return a list. Well, unless…

Understanding the Significance of Interfaces

A counter-consideration here is “am I programming to an interface or in a simple concrete type.” Why does this matter?

Well, it can push back on what I mentioned in the last section. If I’m programming a class called “RandomNumberProvider” with a method “GetMeABunchOfNumbers()” that creates a list, adds a bunch of random numbers to it, and returns that list, then I should probably return List<int>.

But what if I’m designing an interface called IProvideNumbers? Now there is no concrete implementation — no knowledge that what I’m returning is going to be implemented as List everywhere. I’m defining an abstraction, so perhaps I want to leave my options open. Sure RandomNumberProvider that implements the interface only uses a list. But how do I know I won’t later want a second implementation called “DeferredExecutionNumberProvider” that only pops numbers as they’re iterated by clients?

As a TDD practitioner, I find myself programming to interfaces. A lot. And so, I often find myself thinking, what are the postconditions and abilities I want to guarantee to clients across the board?

This isn’t necessarily, itself, a by-product of TDD, but of programming to interfaces. And, with programming to interfaces, specifics can bite you at times. Interfaces are meant to allow flexibility and future-proofing, so getting really detailed in what you supply can tie your hands. If I promise only an IEnumerable, I can later define implementers that do all sorts of interesting things, but if I promise an IList, a lot of that flexibility (such as deferred execution schemes) go out the window.

The Client’s Burden

An interesting way to evaluate some of these tradeoffs is to contemplate what your client’s pain points might be if we guess wrong.

Let’s say we go with IEnumerable as a return type but the client really just wants a IList (or even just List). How bad is the client’s burden? Well, if client only wants to access the objects, it can just awkwardly append .ToList() to the end of each call to the method and have exactly what it wants. If the client wants to modify the state of the grouping (e.g. put the items in a different order and have you cooperate), it’s pretty hosed and can’t really use your services. However, that latter case is addressed by my “when a list is a no brainer” section — if your clients want to do that, you need to not give them an IEnumerable.

What about the flip side? If the client really wants an IEnumerable and you give them a list? Most likely they want IEnumerable for deferred execution purposes, and you will fail at that. There may be other reasons I’m not thinking of off the top, but it seems that erring when client wants an enumerable is kind of a deal-breaker for your code being useful.

Ugh, so what should I do?!?

Clear as mud?

Well, problem is, it’s a complicated subject and I can only offer you my opinion by way of heuristics (unless you want to send me code or gists, and then I can offer concrete opinions and I’m actually happy to do that).

At the broadest level, you should ask yourself what your client is going to be doing with the thing that you return and try to accommodate that. At the next broadest level, you should think to yourself, “do I want to provide the client a feature-rich experience at the cost of later flexibility or do I want to provide the client a more sparse set of behavior guarantees so that I can control more implementation details?”

It also pays to think of the things you’re returning in terms of what they should do (or have done to them), rather than what they are. This is the line of thinking that gets you to ask questions like “will clients need to perform random accesses or sorts,” but it lets you go beyond simple heuristics when engaged in design and really get to the heart of things. Think of what needs to be done, and then go looking for the data type that represents the smallest superset of those things (or, write your own, if nothing seems to fit).

I’ll leave off with what I’ve noticed myself doing in my own code. More often than not, when I’m communicating between application layers I tend to use a lot of interfaces and deal a lot in IEnumerable. When I’m implementing code within a layer, particularly the GUI/presentation layer in which ordering is often important, I favor collections and lists. This is especially true if there is no interface seem between the collaborating components. In these scenarios I’m more inclined to follow the “return the most specific thing possible” heuristic rather than the “be flexible in an interface” heuristic.

Another thing that I do is try to minimize the amount of collections that I pass around an application. The most common use case for passing around bunches of things is collections of data transfer objects, such as some method like “GetCustomersWithFirstName(string firstName).” Clearly that’s going to return a bunch of things. But in other places, I try to make aggregation an internal implementation detail to a class. Command-Query Separation helps with this. If I can, I don’t ask you for a collection, do things to it and hand it back. Instead I say “do this to your collection.”

And finally, when in doubt and all else seems to be a toss-up, I tend to favor promising the least (thus favoring future flexibility). So if I really can’t make a compelling case one way or the other for any reason, I’ll just say “you’re getting an IEnumerable because that makes maintenance programming likely to be less painful later.”

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.

By

I Give Up: Extroverted Barbarians at the Gates

Someone sent me a link to the video shown after this paragraph the other day, and I watched it. I then tweeted the link and sent it to a few of my coworkers because I figured it would make people laugh. It’s really funny, so give it a watch. But weirdly, I didn’t laugh. I watched it over and over again, mesmerized. I recognize that it’s funny and I find it funny, but I didn’t laugh.

https://www.youtube.com/watch?v=BKorP55Aqvg

This video is really a work of genius because it captures some incredible subtleties. There are two common archetypes captured nicely here in the form of the protagonist’s supposed allies: his boss and the project manager. I’ll give them names in their own sections below, along with the client characters. And then there are conversational tactics that bear mentioning.

This all revolves around a protagonist with whom any introverted person can identify. There’s nothing to indicate, per se, whether he’s introverted or extroverted, but the precision, the mannerisms, the posture — all of these scream “programmer” (or at least “engineer”) and so goes the association with introversion. The protagonist is the sole bulwark of sanity against a flood of idiocy, misunderstanding and general incompetence. You probably relate to him, having attended a meeting where all of the gathered C-levels and analysts thought you were being an obstructionist malingerer because you wouldn’t install Angry Birds on the meeting room’s television.

So who are the players?

Chamberlain

In a way, I liken the smarmy project manager, Walter, to former British prime minister, Neville Chamberlain, most remembered for his foreign policy of appeasement leading up to World War II in which he sought to dampen the aggression coming from the Axis powers by essentially “befriending” them. In this particular video, Chamberlain, the project manager, is presumably along to bridge the gap between the non-subject-matter-expert customers and the total-subject-matter-expert protagonist (and whose expertise makes the video eponymous). That’s not really why he’s there (though he doesn’t realize this), and I’ll get into that later as I’m describing tactics.

Chamberlain perceives that his best interests are served by simply agreeing to whatever is happening on the other side of the aisle, improvident though this may be. On some level, he’s probably aware that this strategy is stupid, but, hey, that’s a problem for later. He thinks his boss will skewer him if they don’t get the contract, so the fact that it’s going to be hard or impossible to deliver (what Expert is trying to tell him) just means he’ll later throw someone (i.e., Expert) under the bus.

Dilettante

The “design specialist,” Justine, is a mildly interesting character. She generally looks at Expert with some degree of respect and looks slightly uncomfortable when the rest of the characters make fun of Expert. At one point, to Expert’s delight, she even understands his point, and she visits him after the meeting out of genuine interest in the project and what is probably a “one pro to another” kind of overture. She’s the only character in the room that sees any value in Expert, and she probably recognizes that his subject matter knowledge exceeds hers and has value. If it were just her and Expert, she would probably listen attentively. I call her Dilettante because she seems to be the type of person you encounter with a bit of knowledge in a variety of fields and a genuine interest in improving.

Buffoon

The client’s boss is a classic MacLeod Clueless, and a simple idiot that isn’t very interesting. She’s the classic archetype of an over-promoted middle manager whose value is clearly wrapped up in company tenure. She spouts nonsensical jargon, torpedoes her firm’s own interests throughout the meeting, and serves up her position and her firm’s money for easy pickings by any MacLeod sociopath that happens along. She’s demanding something that she doesn’t understand in a way that makes no sense, and she’s willing to pay any huckster that comes along and sells her the magic beans she’s seeking.

Buffoon

Sociopath

Big Boss Man, to whom Chamberlain reports, is a classic MacLeod Sociopath. He likely has a fairly good handle on the situation and is of the opinion that the clients are idiots, but he has an intuitive understanding of the politics of the situation. Expert is flummoxed by the stupidity of the client proposal, and Chamberlain is simpering in an effort to show his boss his value as a diplomat, believing that the customer is always right and believing that Sociopath also believes that. Sociopath doesn’t. He knows the clients are idiots, and that Chamberlain is also kind of an idiot (for evidence of this, look at his expression at 6:14 where he clearly thinks the discussion of cats and birds as lines is dumb and simply ignores the client).

This doesn’t result in him rushing into defend Expert, however. That’s counter to his best interests, which I’ll address as a tactic, but he also finds Expert somewhat distasteful. Sociopath has navigated his way ably to money and power and a position atop the corporate hierarchy, but it is probably a slight annoyance to him that he may not be the smartest guy in the room. He knows that in Expert’s area of expertise, he’s nowhere near Expert, and while that’s fine, his inability to compare their relative intellectual worth across subject areas is a source of irritation.

Tactical Gamesmanship

So, the ostensible point of this meeting and no doubt many in which you’ve sat is to define the parameters for a project and then successfully launch that project. But, if you were to read the subconscious goals of the players, they would go something like this:

  • Chamberlain: I want to get the client to sign off no matter what, and I want Sociopath to think it was my heroics that made this happen.
  • Buffoon: I want to order people around and show off.
  • Sociopath: I want this to be over quickly so I don’t have to listen to Buffoon and Chamberlain.
  • Dilettante: I want to learn on the job without it being apparent that I’m doing so.
  • Expert: I want to define parameters for this project and successfully launch it.

Sociopath knows that getting Buffoon to agree to the project is a veritable certainty going into the meeting, and he knows that Chamberlain’s presence is valuable, but not for the reasons that Chamberlain thinks. Chamberlain thinks he’s there because he’s a “straight shooter/smooth talker” that “speaks Expert” but Sociopath just wants him there because he understands how to butter Buffoon’s bread — by causing Buffoon to think she’s won an exchange and humbled an Expert. He’s there because Sociopath knows he’ll team up with Buffoon to laugh at Expert. Dilettante is just window dressing.

So what are the tactics by which this happens? What makes this so cathartic for engineers and programmers to watch? Well, there are a number of things occurring here.

Seizing on the only part of an explanation you understand

There’s nothing to level the playing field quite like ignoring most of what someone talking to you says and seizing on some minor point. This has two advantageous for purveyors of rhetorical fallacy. First and foremost, it lets you pivot the discussion in a way that you find favorable, but secondly, it implies that your opponent has babbled on and on and over-complicated the matter (ala Reagan countering Carter — folksy and relatable countering egg-head). Near the beginning, Expert gives a detailed explanation, avoiding saying that it would be impossible to draw red line with green ink by talking about color blindness. It’s a long-winded, but technically accurate way of saying “that’s pretty much impossible,” and all Buffoon takes away from it is “so, in principle this is possible.”

Talking down to the expert because you don’t understand

When Expert asks Buffoon to clarify what she’s talking about with “transparent ink,” she patronizingly says she thought that he’d know what “transparent” means and that he’d better know what “red” means if he’s an Expert. A little later, she doesn’t understand what perpendicular means and when Expert accidentally exposes that, she blames him for not understanding her nonsense. It’s a relatively standard approach to strike first in blaming the other for a miscommunication between two parties, but it’s especially vitriolic in a case where the party in the driver’s seat is covering inadequacy.

Begging the question (and perverting the role of experts)

I’ve encountered this myself, in my travels, and it’s certainly on display here. People assume (from ignorance) that a certain outcome is possible/feasible, and then seek out an expert to make it happen. When the expert explains that they’re misguided or trying to do something ill-advised or impossible, they adopt the stance, “I thought you were an expert, and you’re telling me you can’t do this?” Chamberlain does this throughout the clip.

Dunning Kruger

This mostly comes from Sociopath and somewhat for show, but this is the tendency of those unskilled in a subject to assume that the subject is pretty simple and to generally devalue the knowledge of experts in that field. As more knowledge is acquired, so is respect for experts and humility. Sociopath dresses Expert down, particularly at the point where he says, “look, we’re not asking you to draw 20 lines — just 7.” Buffoon also does this once when she draws a triangle as an example of three perpendicular lines (“move — let me do it!”) Being the only Expert here and thoroughly outgunned and unaware of the real agenda, Expert is absolutely buried in an amplified echo chamber of Dunning Kruger.

Expert Introverts

These players and these tactics are painfully relatable. People in our line of work look at this ruefully and laugh because someone finally gets it and understands how silly the players seem to them. But introversion, lack of interest in office politics, and professional integrity are what hamstring us in such situations. I mean think of it this way — you cringe because you’re right there along with Expert, wanting these idiots to understand that red pens don’t draw green lines. You want to speak rationally to them and use analogies, diagrams and metaphors to make them see your point.

What you don’t do is turn the Dunning Kruger around on them and start telling them that they’re really going to need pure red lines if they want to maximize their verticals and strategize their synergies. You don’t tell them that kitten lines were so 2011. You don’t interrupt Chamberlain when he says “any fool can criticize” to say that you’re okay with the clients’ criticism and how he dare he call them fools. You don’t ask Chamberlain, if his title is “project manager,” why can’t he “manage” to define a clear spec.

You don’t do any of these things. Neither do I. Neither did Expert. Instead, we all do what he did in the end, which is to say, “sure, whatever buddy, I give up.” Extroverts extemporize and thrive in situations like this fueled with BS and beyond their control (though, Sociopath, who is controlling it, may be an introvert). We find ourselves at a loss for words, and utterly demoralized. Our credentials, our competence, and the validity of our very profession called into question, we bleakly resign ourselves to the madness and go home for a beer. We do that for a while, at least, and then, eventually, we Quit with a capital Q.

Perhaps that’s why I didn’t find myself laughing while watching this. Poor Anderson, the Expert, isn’t having an experience that he’ll submit to the Daily WTF and move on — he’s figuring out that his professional life is miserable. And the reason it’s miserable is because he’s realizing that expertise, ideas and results aren’t really the backbone of good business; in the land of the extroverts, egos and social capital are king.